> ## Documentation Index
> Fetch the complete documentation index at: https://supastack.dev/llms.txt
> Use this file to discover all available pages before exploring further.
> For the full documentation corpus in one file, fetch: https://supastack.dev/llms-full.txt

# Aanmelden met een passkey

Wachtwoordloos aanmelden via een browseroverdracht die de sessie terugbrengt naar de app.

## Hoe de overdracht werkt

Aanmelden met een passkey begint in de app en eindigt in de systeembrowser. De app opent {API URL}/auth?mobile_callback=<deep link> via WebBrowser.openAuthSessionAsync; nadat de webpagina een aanmeldmethode heeft voltooid, roept deze GET /api/auth/mobile-handoff aan, die terugredirect naar <scheme>://auth/callback met de sessiecookie en een state-nonce.

Elke poging genereert een verse nonce die ongewijzigd heen en weer moet reizen — een afwijkende state-parameter wordt afgewezen als stateMismatch, zodat een verouderde of vervalste callback geen sessie kan injecteren. De geretourneerde cookie wordt samengevoegd in dezelfde SecureStore-cookiejar die de Better Auth Expo-client gebruikt (supastack.auth_cookie), waarna de sessiestore wordt ingelicht en de aangemelde app rendert.

Een weggedrukt browserblad resulteert in een stil cancelled-resultaat in plaats van een fout, dus laat het aanmeldscherm ongewijzigd als dat gebeurt.

```
# apps/mobile/.env.local
EXPO_PUBLIC_APP_SCHEME=supastack

# apps/web/.env.local — server side
AUTH_PASSKEY_ENABLED=true
MOBILE_ALLOWED_ORIGINS=
```


## Houd de toelatingslijst aan beide kanten identiek

Beide kanten valideren het callbackdoel: de app accepteert alleen <scheme>://auth plus de geconfigureerde productie-origins, en de server controleert dezelfde lijst die is opgebouwd uit EXPO_PUBLIC_APP_SCHEME en MOBILE_ALLOWED_ORIGINS. Callbacks met inloggegevens, onbekende schema's of lookalike-achtervoegsels worden afgewezen voordat er ook maar een cookie beweegt.

In productie is MOBILE_ALLOWED_ORIGINS vereist en moet deze exacte, niet-lokale HTTPS-origins bevatten — wildcards worden niet geaccepteerd. De app wordt gebundeld meegeleverd terwijl de server zijn omgeving per request leest, dus een schema- of originwijziging vereist zowel een nieuwe app-build als een serverdeploy; wie slechts één kant wijzigt, laat overdrachten gesloten falen.


## De andere wachtwoordloze methoden

Hetzelfde aanmeldscherm biedt eenmalige e-mailcodes (requestEmailOtp gevolgd door verifyEmailOtp) en sociale aanmelding via Apple of Google via signIn.social met een callbackURL. Passkeys verschijnen wanneer AUTH_PASSKEY_ENABLED=true op de server staat; de passkey- en tweefactorinstellingen van een account blijven in de webapp onder Instellingen → Beveiliging.


## Verificatie en probleemoplossing

Oefen op de beoogde build een callback bij koude start, een terugkeer naar een draaiende app, een geannuleerd browserblad en een verlopen sessie. De getypeerde fouten — passkeyUnavailable, browserFailed, untrustedCallback, missingCookie, malformedCookie, cookieStoreFailed — beschrijven elk een eigen breuk; stateMismatch betekent dat de nonce niet ongewijzigd heen en weer reisde en de poging terecht is geweigerd.

Als elke overdracht wordt afgewezen, vergelijk dan EXPO_PUBLIC_APP_SCHEME in de uitgebrachte build met het schema van de server en MOBILE_ALLOWED_ORIGINS — het paar loopt uiteen wanneer de ene kant opnieuw is gedeployd zonder de andere.


## Volgende

[Mobiele API](https://supastack.dev/nl/docs/mobile/api.md)
