'use client' import { useEffect, useState } from 'react' import { AlertCircle, Fingerprint, Loader2 } from 'lucide-react' import { passkeyAnmeldungAbschliessen, passkeyAnmeldungStarten } from '@/server/actions/passkey' import { browserSupportsWebAuthn, passkeyBrowserfehler, startAuthentication, } from '@/lib/passkey-browser' import { Alert, AlertDescription } from '@/components/ui/alert' import { Button } from '@/components/ui/button' /** * Knopf "Mit Passkey anmelden" auf der Anmeldeseite. * * Der Ablauf ist dreiteilig: Optionen vom Server holen, das Geraet fragen, * die Antwort zurueckschicken. Gelingt der letzte Schritt, leitet die Server * Action weiter - dieser Baustein sieht das Ergebnis dann gar nicht mehr. * * Sichtbar ist der Knopf nur, wenn der Server ihn anbietet (https) UND der * Browser WebAuthn kann. Die zweite Pruefung laeuft erst nach dem ersten * Rendern: Auf dem Server gibt es kein navigator-Objekt, und ein Knopf, der * beim Laden verschwindet, ist unangenehmer als einer, der kurz spaeter * erscheint. */ export function PasskeyAnmeldung({ weiter }: { weiter: string }) { const [laeuft, setLaeuft] = useState(false) const [fehler, setFehler] = useState(null) const [browserKann, setBrowserKann] = useState(false) useEffect(() => { setBrowserKann(browserSupportsWebAuthn()) }, []) async function anmelden() { setFehler(null) setLaeuft(true) try { const start = await passkeyAnmeldungStarten() if (!start.ok) { setFehler(start.fehler) return } const antwort = await startAuthentication({ optionsJSON: start.optionen, }) const ergebnis = await passkeyAnmeldungAbschliessen(JSON.stringify(antwort), weiter) // Bei Erfolg wird gar nichts zurueckgegeben - die Action leitet weiter. if (!ergebnis.ok) setFehler(ergebnis.fehler) } catch (ausnahme) { setFehler(passkeyBrowserfehler(ausnahme)) } finally { setLaeuft(false) } } if (!browserKann) return null return (
oder
{fehler && ( )}

Fingerabdruck, Gesicht oder Geräte-PIN — ohne E-Mail und Passwort.

) }