feat(auth): make passkey enrollment optional on first login

Remove passkey requirement from user onboarding flow
Update UI badges to show passkeys as optional rather than pending
Update documentation to reflect the new behavior
This commit is contained in:
2026-04-27 13:25:05 +08:00
parent c214d643dd
commit 06165f80db
4 changed files with 11 additions and 10 deletions

View File

@@ -8,7 +8,7 @@ Nuxt 4 app with:
- Redis-backed sessions and WebAuthn challenge storage - Redis-backed sessions and WebAuthn challenge storage
- Seeded `xiaomai` super-admin account - Seeded `xiaomai` super-admin account
- Super-admin user creation and password reset flow - Super-admin user creation and password reset flow
- First-login enforcement: temporary password change plus passkey enrollment - First-login enforcement: temporary password change
## Environment ## Environment
@@ -47,7 +47,7 @@ The backend bootstraps its schema automatically on startup and seeds this initia
- Username: `xiaomai` - Username: `xiaomai`
- Temporary password: `123456` - Temporary password: `123456`
On first login, the user is forced to change that temporary password and register a passkey before accessing the protected area. On first login, the user is forced to change that temporary password before accessing the protected area. Passkey enrollment is available from Security, but optional.
## Production ## Production
@@ -136,7 +136,8 @@ docker compose -f docker-compose.yml -f docker-compose.dev.yml restart app
- Password login with Redis-backed session cookie - Password login with Redis-backed session cookie
- Passkey login using WebAuthn discoverable credentials - Passkey login using WebAuthn discoverable credentials
- Super admin creates users with default password `123456` - Super admin creates users with default password `123456`
- Users must change password and set a passkey after first login - Users must change password after first login
- Users can optionally register a passkey from Security
- Users can change their own password from Security - Users can change their own password from Security
- Super admin can reset a user's password back to `123456` - Super admin can reset a user's password back to `123456`

View File

@@ -93,8 +93,8 @@
size="sm" size="sm"
/> />
<UBadge <UBadge
:label="row.original.needsPasskeySetup ? 'Passkey pending' : 'Passkey ready'" :label="row.original.passkeyCount > 0 ? 'Passkey ready' : 'No passkey'"
:color="row.original.needsPasskeySetup ? 'warning' : 'success'" :color="row.original.passkeyCount > 0 ? 'success' : 'neutral'"
variant="soft" variant="soft"
size="sm" size="sm"
/> />

View File

@@ -59,8 +59,8 @@
</div> </div>
<UBadge <UBadge
:label="passkeys.length > 0 ? 'Ready' : 'Required'" :label="passkeys.length > 0 ? 'Ready' : 'Optional'"
:color="passkeys.length > 0 ? 'success' : 'warning'" :color="passkeys.length > 0 ? 'success' : 'neutral'"
variant="soft" variant="soft"
/> />
</div> </div>

View File

@@ -93,13 +93,13 @@ export interface PasskeySummary {
} }
export function needsUserOnboarding( export function needsUserOnboarding(
user: Pick<AuthUser, 'mustChangePassword' | 'needsPasskeySetup'> | null | undefined user: Pick<AuthUser, 'mustChangePassword'> | null | undefined
) { ) {
return Boolean(user && (user.mustChangePassword || user.needsPasskeySetup)) return Boolean(user?.mustChangePassword)
} }
export function getDefaultAuthenticatedPath( export function getDefaultAuthenticatedPath(
user: Pick<AuthUser, 'role' | 'mustChangePassword' | 'needsPasskeySetup'> user: Pick<AuthUser, 'role' | 'mustChangePassword'>
) { ) {
if (needsUserOnboarding(user)) { if (needsUserOnboarding(user)) {
return '/security' return '/security'