- Resolve org role names to Logto role IDs in invite and role change flows
(fixes entity.relation_foreign_key_not_found on invite)
- Handle existing Logto users on re-invite instead of failing with
email_already_in_use
- Delete users from Logto when removed from last org membership
- Consolidate tenant settings page into 3 cards: Tenant Details, MFA,
Authentication Policy — remove duplicate MFA Enforcement and Change
Password (now in Account Settings)
- Make passkey list scrollable
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Same fix as registration verify — @simplewebauthn/browser returns
type: "public-key" but Logto expects type: "WebAuthn".
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
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>
Bootstrap only set [Totp, BackupCode] — WebAuthn was missing. Now
matches LogtoStartupConfig: all three factors available from first boot.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Two fundamental fixes:
- user.missing_mfa now triggers MfaEnrollmentError (enroll UI) instead
of MfaRequiredError (verify UI). Users without MFA were shown a TOTP
code prompt they couldn't fill.
- Logto MFA factors always set to [Totp, WebAuthn, BackupCode] with
UserControlled policy on startup. Availability is always-on for all
users. The vendor auth policy controls enforcement (via
MfaEnforcementFilter), not what Logto offers during sign-in.
- Removed syncMfaConfigToLogto from VendorAuthPolicyController — vendor
policy changes no longer modify Logto's sign-in experience.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
- Profile API returns empty string instead of "null" when Logto user
has no display name set (String.valueOf(null) → "null" bug).
- SettingsPage: add overflowY auto + flex 1 so content scrolls within
the AppShell layout (which uses overflow: hidden).
- Remove redundant passkey offer from onboarding page — passkey
enrollment now happens during sign-in via the Experience API.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
When MFA mode is off but passkeys are enabled, WebAuthn + BackupCode
factors are still synced to Logto. Previously, MFA off cleared all
factors including WebAuthn, so passkey enrollment was never offered.
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>
Logto's /api/my-account/ endpoints reject the opaque access token with
401 even though /api/verifications/ accepts it. The bind step now goes
through the SaaS backend which calls the Management API instead.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Logto Account API requires identity verification (logto-verification-id
header) for sensitive MFA operations. Adds a password prompt modal before
the WebAuthn ceremony — verifies password first, then proceeds with
passkey registration using the verification record ID.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Vendor sidebar collapsed and tenant sidebar appeared when navigating to
/settings/account because onVendorRoute was false for non-/vendor paths.
Now vendor users stay on vendor sidebar for all routes except /tenant/*.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Logto's PATCH /api/account-center expects mfa as 'Off'|'ReadOnly'|'Edit',
not a nested object. Fixes 400 Bad Request on startup.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
- Sync vendor auth policy to Logto sign-in experience on save and on
startup. Always include WebAuthn + TOTP + BackupCode in MFA factors
when MFA is enabled — no reason to gate passkeys behind a toggle.
- Enable Logto Account Center on startup for user-facing MFA management.
- Add passkey registration to account settings via Logto Account API.
Frontend calls Logto directly (same domain) for the WebAuthn ceremony:
generate options, browser credential creation, verify, and bind.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Three fixes for MFA enrollment and sign-in:
- Defer TOTP registration with Logto until after 6-digit code verification.
Previously setupTotp() immediately registered the secret, so abandoning
enrollment mid-way left MFA active without a working authenticator.
- Move entire MFA enrollment flow (QR code, verify, backup codes) into a
Modal dialog instead of replacing the Card content inline.
- Fix sign-in MFA flow: submitMfa() no longer calls identifyUser() after
TOTP verify — user is already identified, and passing the MFA
verificationId to identification returned 422 ("method not activated").
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>
Logto's secretQrCode is a data:image/png;base64 URI, not an otpauth://
string. QRCodeSVG crashes trying to encode it ("Data too long"). Now
renders data URIs as <img> and only uses QRCodeSVG for otpauth:// URIs.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Logto's /api/roles/{id}/users endpoint rejects page=1 with
guard.invalid_pagination. Remove explicit pagination params and
let Logto use its defaults.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
The TenantPortalService constructor gained an AccountService parameter
in the consolidation refactor — the test was missing it.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
- Remove dead IllegalArgumentException catch blocks in TenantPortalController
(delegated methods now throw ResponseStatusException, handled by Spring)
- Add password reset notification email in VendorAdminService.resetAdminPassword
- Add verifyIsVendorAdmin guard to resetAdminPassword and resetAdminMfa
to prevent platform admins from resetting arbitrary non-admin users
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Vendor admins use global roles, not org roles — passing null orgId
would previously cause addUserToOrganization to call
/api/organizations/null/users and fail.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Adds verifyUserPassword (for current-password check before password change) and
four global role methods (listRoleUsers, getRoleByName, assignGlobalRole,
revokeGlobalRole) needed by the upcoming AccountService and VendorAdminService.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Two features: multi-vendor admin management (invite/create, remove,
reset password/MFA) and shared account settings page (profile, password
change with current-password verification, MFA self-service). Includes
consolidation plan extracting user-level identity operations from
TenantPortalService into new AccountService.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
- Add V002/V003 migrations and VendorAuthPolicy classes to CLAUDE.md
- Document MFA & passkey enforcement model in config CLAUDE.md
- Mark passkey MFA design spec as Implemented
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
- Change auth-settings endpoint from PUT to PATCH (matches partial update semantics and frontend hook)
- Add @PreAuthorize("SCOPE_tenant:manage") to updateAuthSettings endpoint
- Consolidate MFA/passkey 403 redirect handling in API client
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
After tenant creation, checks vendor auth policy and conditionally
shows a passkey enrollment offer screen before redirecting. User
can skip and set up later.
Co-Authored-By: Claude Sonnet 4.6 <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>
Adds startWebAuthnAuth and verifyWebAuthnAuth functions that call
the Logto Experience API WebAuthn endpoints for passkey MFA verification.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Adds /vendor/auth-policy route with MFA mode (off/optional/required) and passkey (enabled/disabled, optional/preferred/required mode) controls, including a confirmation guard before enforcing required MFA.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Adds hooks for listing/renaming/deleting passkeys, MFA method preference,
tenant auth settings, and vendor auth policy (using the new putJson method).
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>