Four fixes for the MFA sign-in flow:
1. Fix passkey verify crash: extract authenticationOptions from Logto
response (was passing full response as optionsJSON). Pass
verificationId to the verify endpoint.
2. Default to passkey verification when no MFA method preference is
stored (was showing method picker which offered TOTP to passkey-only
users).
3. Show backup codes after MFA enrollment: new mfaEnrollBackupCodes
mode with copy/download buttons and confirmation checkbox. Users
must save codes before completing sign-in.
4. Remove duplicate error alerts in enrollment screens (top-level
alert handles all modes).
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
- TOTP secret: /verification/totp/secret (not /verification/totp)
- Backup codes: generate via /verification/backup-code/generate first,
then bind with the returned verificationId. Cannot bind BackupCode
without generating codes first.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
- Bind BackupCode after primary MFA factor (WebAuthn or TOTP) to satisfy
Logto's requirement that backup codes accompany any MFA method.
- Add TOTP enrollment option alongside passkey on the enrollment screen:
"Use passkey" / "Use authenticator app" / "Set up later".
- TOTP enrollment shows QR code + secret + 6-digit verification inline
in the sign-in UI, using Experience API endpoints.
- Added createTotpSecret() and verifyTotpSetup() to experience-api.ts.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Remove the SaaS backend proxy approach for passkey registration (Account
API binding, Management API proxy, password modal in PasskeySection).
Instead, offer passkey enrollment natively during sign-in via Logto's
Experience API — the correct architectural layer.
Sign-in flow: when Logto returns MFA enrollment available (422), show a
"Secure your account" screen with Register passkey / Set up later. Uses
Experience API WebAuthn registration endpoints. Works for all users
(SaaS and future server users) since the sign-in UI is shared.
PasskeySection in account settings now only manages existing passkeys
(list/rename/delete) and directs users to register during sign-in.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Repositions the "Forgot password?" link from above the sign-in button
to below it, matching the desired layout. Updates link style to be
centered with link color instead of right-aligned muted text.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Adds mfaWebauthn and mfaMethodPicker modes with smart routing based on
stored preference (localStorage). Auto-triggers passkey prompt on mode
entry. Adds "Use passkey instead" link in TOTP mode. Saves method
preference on successful verification.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
In SaaS mode, SAAS_ADMIN_USER must be an email address. It's used as
both the Logto username and primaryEmail. No separate SAAS_ADMIN_EMAIL.
Installer enforces email format in SaaS mode (moved deployment mode
question before admin credentials), accepts any username in standalone.
Sign-in form label changed to "Login".
Removes SAAS_ADMIN_EMAIL from bootstrap, compose template, installers,
and all documentation.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Fetch /api/.well-known/sign-in-exp on mount and check signInMode.
If not SignInAndRegister, hide the "Sign up" link and force sign-in
mode (even if ?first_screen=register was in the URL).
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Newer Logto versions redirect to /register?app_id=... instead of
/sign-in?first_screen=register. Check the pathname in addition to
the query param so the registration form shows correctly.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Show "Please enter a valid email address" when the user enters a
username instead of an email in the sign-up form, rather than letting
it hit Logto's API and returning a cryptic 400.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Rename Java packages from net.siegeln.cameleer3 to net.siegeln.cameleer,
update all references in workflows, Docker configs, docs, and bootstrap.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
- Sidebar, sign-in page, and favicons all use the single SVG
- Postinstall copies SVG for SaaS HTML favicon (gitignored)
- Sign-in favicon committed (baked into Logto Docker image)
- Remove old PNG favicon references
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
- Sidebar and sign-in logos use Vite import from @cameleer/design-system
- HTML favicons copied by postinstall script (gitignored)
- Remove manually copied PNGs from repo
- Clean up SecurityConfig permitAll (bundled assets under /_app/**)
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
- Replace favicon SVG with official camel-logo.svg from design-system
- Add PNG favicons (32px, 192px) with proper link tags in index.html
- Replace sidebar logo with 48px brand icon (cameleer-logo-48.png)
- Replace sign-in page logo with 48px brand icon
- Permit favicon PNGs in SecurityConfig
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
The sign-in page is served by Logto, not the SaaS app. Referencing
/platform/favicon.svg required SecurityConfig permitAll and cross-service
routing. Instead, bundle favicon.svg directly in the sign-in UI dist
so Logto serves it at /favicon.svg.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Replace Logto's default sign-in page with a custom React SPA that
matches the cameleer3-server login page using @cameleer/design-system.
- New Vite+React app at ui/sign-in/ with Experience API integration
- 4-step auth flow: init → verify password → identify → submit
- Design-system components: Card, Input, Button, FormField, Alert
- Same witty random subtitles as cameleer3-server LoginPage
- Dockerfile: add sign-in-frontend build stage, copy dist to image
- docker-compose: CUSTOM_UI_PATH on Logto, shared signinui volume
- SaaS entrypoint copies sign-in dist to shared volume on startup
- Add .gitattributes for LF line endings
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>