'use client' import { useState } from 'react' import { useRouter } from '../contexts/RouterContext' import { useConfig } from '../contexts/AuthContext' import { useAllauthAPI } from '../contexts/APIContext' import { useAuthContext } from '../contexts/AuthContext' import { useStyles } from '../contexts/StylesContext' interface PasskeyLoginProps { onSuccess?: () => void } export function PasskeyLogin({ onSuccess }: PasskeyLoginProps) { const router = useRouter() const config = useConfig() const api = useAllauthAPI() const { refresh } = useAuthContext() const styles = useStyles() const [error, setError] = useState(null) const [authenticating, setAuthenticating] = useState(false) // Check if passkey login is enabled const passkeyLoginEnabled = config?.data?.mfa?.passkey_login_enabled if (!passkeyLoginEnabled) { return null } const handlePasskeyLogin = async () => { setError(null) setAuthenticating(true) try { const { startAuthentication } = await import('@simplewebauthn/browser') // Get login options (challenge) from server const optionsRes = await api.webauthn.requestOptions.login() if (optionsRes.status !== 200) { throw new Error('Failed to get login options') } // Extract publicKey options - allauth returns { request_options: { publicKey: {...} } } const publicKeyOptions = optionsRes.data?.request_options?.publicKey if (!publicKeyOptions?.challenge) { throw new Error('Invalid login options') } // Perform WebAuthn authentication in browser // @simplewebauthn/browser v13+ expects { optionsJSON: ... } const credential = await startAuthentication({ optionsJSON: publicKeyOptions as any }) // Submit credential to server for login const res = await api.webauthn.login(credential) if (res.status === 200) { await refresh() if (onSuccess) { onSuccess() } else { const next = router.searchParams.get('next') router.push(next?.startsWith('/') ? next : '/dashboard') } } else { setError('Login failed. Please try again.') } } catch (e: any) { if (e.name === 'AbortError' || e.name === 'NotAllowedError') { // User cancelled - not an error setError(null) } else { setError(e.message || 'Failed to sign in with passkey') } } finally { setAuthenticating(false) } } return (
or
{error && (

{error}

)}
) }