Passkey browser compatibility: detect support, magic link fallback

- Login: hide passkey button when browser lacks WebAuthn, default to
  magic link mode, hide "back to passkey" link
- Register: detect passkey support and offer magic link registration as
  fallback. New server-side registerWithMagicLink() creates account
  without credential and sends verification email.
- Home: show passkey count for logged-in users, show amber unsupported
  message instead of hiding the add-passkey prompt entirely
- i18n: add passkeyNotSupported, passkeyNotSupportedRegister,
  registerWithMagicLink, passkeyStatus keys (en + de)

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
This commit is contained in:
Ullrich Schäfer 2026-03-29 09:54:37 +02:00
parent 9c7891402f
commit 9adf9b977a
No known key found for this signature in database
GPG key ID: A32FF691A0F752D9
7 changed files with 199 additions and 30 deletions

View file

@ -106,6 +106,8 @@ export default {
addPasskey: "Passkey hinzufügen",
settingUp: "Wird eingerichtet...",
passkeyAdded: "Passkey hinzugefügt! Du kannst dich jetzt sofort auf diesem Gerät anmelden.",
passkeyStatus: "{{count}} Passkey registriert",
passkeyStatus_other: "{{count}} Passkeys registriert",
routes: {
title: "Routen",
myRoutes: "Meine Routen",
@ -147,6 +149,9 @@ export default {
registerDescription: "Registriere dich mit einem Passkey — kein Passwort nötig.",
registerWithPasskey: "Mit Passkey registrieren",
creatingPasskey: "Erstelle Passkey...",
passkeyNotSupported: "Dein Browser unterstützt keine Passkeys. Bitte verwende einen anderen Browser zur Registrierung.",
passkeyNotSupportedRegister: "Dein Browser unterstützt keine Passkeys. Du kannst dich stattdessen per Magic Link registrieren und später einen Passkey hinzufügen.",
registerWithMagicLink: "Per Magic Link registrieren",
},
},
} as const;

View file

@ -106,6 +106,8 @@ export default {
addPasskey: "Add Passkey",
settingUp: "Setting up...",
passkeyAdded: "Passkey added! You can now sign in instantly on this device.",
passkeyStatus: "{{count}} passkey registered",
passkeyStatus_other: "{{count}} passkeys registered",
routes: {
title: "Routes",
myRoutes: "My Routes",
@ -147,6 +149,9 @@ export default {
registerDescription: "Register with a passkey — no password needed.",
registerWithPasskey: "Register with Passkey",
creatingPasskey: "Creating passkey...",
passkeyNotSupported: "Your browser does not support passkeys. Please use a different browser to register.",
passkeyNotSupportedRegister: "Your browser doesn't support passkeys. You can register with a magic link instead and add a passkey later from a supported browser.",
registerWithMagicLink: "Register with Magic Link",
},
},
} as const;