Passkeys
Passkey (WebAuthn) endpoints for passwordless register/login and managing credentials on an existing account.
DI
builder.Services.AddPasskeyEndpoints<AppUser>();
This registers passkey rate limits/ReAuth and the default IdentityPasskeySignInCompleter<AppUser>. Prefer the generic overload for compose hosts so register/login can resolve IPasskeySignInCompleter<TUser>.
Facade: passkeys are enabled by default; set Passkeys.ServerDomain (required in Production).
Map
app.MapGroup("/account").MapPasskeyEndpoints<AppUser>();
Routes are mapped under {prefix}/passkeys (facade default /account/passkeys).
Routes
| Method | Path | Auth / extras |
|---|---|---|
POST | /passkeys/creationOptions | Auth + ReAuth + CSRF + rate limit |
POST | /passkeys/requestOptions | CSRF + rate limit; optional ?username= |
POST | /passkeys/register/options | CSRF; body { email } |
POST | /passkeys/register | CSRF; passwordless create + completer sign-in |
POST | /passkeys/login | CSRF; completer sign-in (useCookies / useSessionCookies for Identity completer) |
POST | /passkeys/ | Add passkey (auth + ReAuth + CSRF) |
GET | /passkeys/ | List passkeys (auth) |
PATCH | /passkeys/ | Rename (auth + ReAuth + CSRF) |
DELETE | /passkeys/{credentialIdUrl} | Remove (auth + ReAuth + CSRF) |
Passwordless register flow
POST /account/passkeys/register/optionswith{ "email": "..." }- Browser
navigator.credentials.create(...) POST /account/passkeys/registerwith{ "email": "...", "credentialJson": "..." }
Sign-in completer
After a successful register/login ceremony, AuthEndpoints calls IPasskeySignInCompleter<TUser>.
Default: Identity
IdentityPasskeySignInCompleter honors the same query flags as Identity login:
?useCookies=true→ persistent application cookie?useSessionCookies=true→ session application cookie- neither → Identity bearer token (
AccessTokenResponse)
Register also returns PasskeyCredentialResponse (credential id) after Identity sign-in.
Simple JWT
Register JwtPasskeySignInCompleter instead (requires AddJwtEndpoints):
builder.Services.AddPasskeyEndpoints<AppUser>();
builder.Services.AddJwtEndpoints<AppUser, AppDbContext>(o =>
{
o.Issuer = "https://example.com";
o.Audience = "https://example.com";
o.SigningOptions.SymmetricKey = builder.Configuration["Jwt:SymmetricKey"];
});
builder.Services.AddPasskeySignInCompleter<AppUser, JwtPasskeySignInCompleter<AppUser>>();
Successful passkey register/login then returns the same shape as JWT /create: access token in JSON + HttpOnly refresh cookie. Cookie query flags are ignored for this completer.
Facade JWT opt-in does not auto-select the JWT completer — register it explicitly when you want Simple JWT after passkeys.
Constraints
- Passwordless register needs
IdentityUserwithstringorGuidkey. - CSRF is required for WebAuthn ceremonies.
- Sensitive credential mutations require ReAuth.