Getting Started
Register a confirmed account
SPA password and passkey signup when RequireConfirmedAccount is true.
Build a first-party SPA signup that stays logged out until the user confirms email, then signs in. Use this when RequireConfirmedAccount is true (the facade default).
Assume the cookie facade: management and cookie login under /identity, passkeys under /account. See Quick start and Recipes.
Shared setup
- Offer Password and Passkey on the same signup screen.
- Call
GET /identity/csrfTokenbefore unsafe POSTs that require antiforgery. Send the value as headerRequestVerificationToken. - After a successful register (
200), show the same Check your email screen for both methods. Do not treat that200as signed in. - Do not tell the user the email is already registered. Duplicate-email paths return generic success or a generic failure (see below).
Password register
- Collect email and password.
POST /identity/registerwith body{ "email", "password" }and CSRF.- On
200, show Check your email. Stay logged out. Duplicate email also returns200(anti-enumeration). Use the same copy. - On validation failure, show the
400problem details. - The mail link calls
GET /identity/confirmEmail?userId=…&code=….- With
EmailConfirmation.ConfirmEmailRedirectUriunset: success is plain-text thank-you (200); failure is401. - With the URI set: success and failure return
302to that URI withstatus=confirmed|failedandflow=confirm(orflow=change-emailwhenchangedEmailis present). Configure the option under Email confirmation.
- With
- After confirm, sign in:
POST /identity/loginwith email and password. Use?useSessionCookies=falseonly when you need a persistent cookie. See Cookie auth. - On login success, enter the app with the session cookie (
credentials: "include").
Passkey register
- Collect email only.
POST /account/passkeys/register/optionswith{ "email" }and CSRF. Creation options are returned even when the email is already taken.- Run
navigator.credentials.create(…). If the user cancels, show a soft UI error. Do not call register. POST /account/passkeys/register?useCookies=truewith{ "email", "credentialJson" }and CSRF.- New email success:
200with{ "credentialId" }(or equivalentPasskeyCredentialResponse). No Identity application cookie while the account is unconfirmed. Show the same Check your email screen. You may add a short note that they registered with a passkey. - Email taken, bad ceremony, or an attempt to attach to an existing user id: generic
400"Unable to complete registration." Use that copy. Do not invent a more specific reason. - Confirm with the same mail link and
GET /identity/confirmEmailbehavior as password register. The passkey is already stored on the unconfirmed user. - After confirm, sign in with passkey:
POST /account/passkeys/requestOptions(optional?username=).navigator.credentials.get(…).POST /account/passkeys/login?useCookies=truewith the assertion payload and CSRF.
- Login succeeds only after confirm. Unconfirmed login returns
401Invalid credentials.
Default passkey completer cookie flags follow Identity Login, not facade LoginCookie. See Passkeys.
Host checklist
| Do | Do not |
|---|---|
| Same check-email screen for password and passkey | Treat register 200 as logged in |
| Generic copy on duplicate email | Say "email already registered" |
| Sign in only after confirm | Expect a session from unconfirmed passkey register |
Out of scope
This page does not cover sign-in inside confirmEmail, public resend without a session, or OAuth.