Commit Graph

21 Commits

Author SHA1 Message Date
hsiegeln
0481cefaf4 fix: sign-in MFA flow overhaul — passkey verify, backup codes, defaults
All checks were successful
CI / build (push) Successful in 2m19s
CI / docker (push) Successful in 1m4s
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>
2026-04-27 20:49:32 +02:00
hsiegeln
040ae60be5 fix: correct Experience API endpoints for TOTP and backup codes
All checks were successful
CI / build (push) Successful in 2m4s
CI / docker (push) Successful in 1m1s
- 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>
2026-04-27 19:30:54 +02:00
hsiegeln
d8f7452ab7 feat: full MFA enrollment during sign-in — passkey + TOTP + backup codes
All checks were successful
CI / build (push) Successful in 2m2s
CI / docker (push) Successful in 1m10s
- 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>
2026-04-27 19:22:53 +02:00
hsiegeln
18e6f32f90 refactor: move passkey enrollment to sign-in UI via Experience API
All checks were successful
CI / build (push) Successful in 2m12s
CI / docker (push) Successful in 1m49s
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>
2026-04-27 18:33:46 +02:00
hsiegeln
9231a1fc60 fix: move forgot password link below sign-in button
All checks were successful
CI / build (push) Successful in 2m0s
CI / docker (push) Successful in 1m7s
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>
2026-04-27 16:06:36 +02:00
hsiegeln
76a62135ab feat: add WebAuthn and method picker modes to sign-in UI
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>
2026-04-27 08:55:16 +02:00
hsiegeln
6c70efcb54 feat: add MFA verification (TOTP + backup code) to sign-in flow
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-04-26 13:44:28 +02:00
hsiegeln
1f3a9551c5 feat: add forgot-password UI flow to custom sign-in page
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-04-26 13:42:51 +02:00
hsiegeln
08a3ad03b7 feat: add forgot-password and MFA verification Experience API functions
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-04-26 13:39:31 +02:00
hsiegeln
8fe18c7f83 feat: unify admin identity — SAAS_ADMIN_USER is the email in SaaS mode
All checks were successful
CI / build (push) Successful in 1m56s
CI / docker (push) Successful in 1m32s
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>
2026-04-25 20:46:24 +02:00
hsiegeln
9bf6c17d63 fix: hide registration option when sign-in mode is SignIn only
Some checks failed
CI / build (push) Successful in 2m4s
CI / docker (push) Has been cancelled
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>
2026-04-25 20:06:17 +02:00
hsiegeln
0cfa359fc5 fix(sign-in): detect register mode from URL path, not just query param
All checks were successful
CI / build (push) Successful in 1m19s
CI / docker (push) Successful in 44s
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>
2026-04-25 10:10:57 +02:00
hsiegeln
b066d1abe7 fix(sign-in): validate email format before registration attempt
All checks were successful
CI / build (push) Successful in 1m17s
CI / docker (push) Successful in 46s
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>
2026-04-25 09:41:41 +02:00
hsiegeln
9ed2cedc98 feat: self-service sign-up with email verification and onboarding
All checks were successful
CI / build (push) Successful in 1m14s
CI / docker (push) Successful in 1m15s
Complete sign-up pipeline: email registration via Logto Experience API,
SMTP email verification, and self-service trial tenant creation.

Layer 1 — Logto config:
- Bootstrap Phase 8b: SMTP email connector with branded HTML templates
- Bootstrap Phase 8c: enable SignInAndRegister (email+password sign-up)
- Dockerfile installs official Logto connectors (ensures SMTP available)
- SMTP env vars in docker-compose, installer templates, .env.example

Layer 2 — Experience API (ui/sign-in/experience-api.ts):
- Registration flow: initRegistration → sendVerificationCode → verifyCode
  → addProfile (password) → identifyUser → submit
- Sign-in auto-detects email vs username identifier

Layer 3 — Custom sign-in UI (ui/sign-in/SignInPage.tsx):
- Three-mode state machine: signIn / register / verifyCode
- Reads first_screen=register from URL query params
- Toggle links between sign-in and register views

Layer 4 — Post-registration onboarding:
- OnboardingService: reuses VendorTenantService.createAndProvision(),
  adds calling user to Logto org as owner, enforces one trial per user
- OnboardingController: POST /api/onboarding/tenant (authenticated only)
- OnboardingPage.tsx: org name + auto-slug form
- LandingRedirect: detects zero orgs → redirects to /onboarding
- RegisterPage.tsx: /platform/register initiates OIDC with firstScreen

Installers (install.sh + install.ps1):
- Both prompt for SMTP config in SaaS mode
- CLI args, env var capture, cameleer.conf persistence

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-25 00:21:07 +02:00
hsiegeln
63c194dab7 chore: rename cameleer3 to cameleer
Some checks failed
CI / build (push) Failing after 18s
CI / docker (push) Has been skipped
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>
2026-04-15 15:28:44 +02:00
hsiegeln
f9b1628e14 fix: add password visibility toggle and fix branding to 'Cameleer'
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-04-09 19:49:14 +02:00
hsiegeln
2f7d4bd71c feat: use cameleer3-logo.svg from design-system v0.1.36 everywhere
All checks were successful
CI / build (push) Successful in 1m7s
CI / docker (push) Successful in 3m34s
- 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>
2026-04-06 23:03:18 +02:00
hsiegeln
2e87667734 refactor: import brand icons directly from design-system package
Some checks failed
CI / build (push) Failing after 20s
CI / docker (push) Has been skipped
- 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>
2026-04-06 22:39:29 +02:00
hsiegeln
29daf51ee3 feat: replace icons with brand assets from design-system v0.1.32
All checks were successful
CI / build (push) Successful in 1m29s
CI / docker (push) Successful in 3m22s
- 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>
2026-04-06 22:09:13 +02:00
hsiegeln
983b861d20 fix: bundle favicon.svg in sign-in UI instead of cross-service fetch
All checks were successful
CI / build (push) Successful in 40s
CI / docker (push) Successful in 22s
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>
2026-04-06 15:35:23 +02:00
hsiegeln
df220bc5f3 feat: custom Logto sign-in UI with Cameleer branding
All checks were successful
CI / build (push) Successful in 40s
CI / docker (push) Successful in 50s
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>
2026-04-06 11:43:22 +02:00