Authentication
A complete, production-shaped auth system with beautiful split-panel screens (brand showcase + form), verified in light, dark, and mobile.

Register & confirm email
/register creates an account and sends a confirmation link (in dev, to the server log). Until the address is confirmed, sign-in is blocked when RequireConfirmedEmail is on, and a "resend confirmation" path is included. Responses never reveal whether an email exists, so the flow doesn't leak account enumeration.
New sign-ups are granted a default role (the Account.DefaultRole setting, default Member) so their first sign-in lands on a usable app rather than an empty shell. Self-service registration can be turned off (Account.AllowRegistration) for invite-only instances.
Sign in & out
/login takes email + password with an optional Remember me (persistent vs session cookie). Failed attempts count toward lockout (5 attempts → a 15-minute lockout).
Passwords
/forgot-password emails a reset link; /reset-password completes it. Signed-in users change their password from their profile. Changing a password rotates the security stamp, which invalidates other sessions.
Two-factor authentication (TOTP)
From Profile → Two-factor, users enrol with any authenticator app by scanning a QR code; enrolment issues one-time recovery codes. At login, a 2FA user completes a second step with a 6-digit code or a recovery code. 2FA can be disabled or recovery codes regenerated at any time.
Per-device sessions
Every sign-in records a session (device, browser/OS, IP, last-seen). Profile → Active sessions lists them and lets a user sign out a single device or sign out all others. Revocation is near-instant: the cookie is re-validated on a 1-minute interval, so a killed session stops working within ~1 minute without disturbing other devices.
OAuth sign-in & account linking
Google, Microsoft, and GitHub are supported and config-gated — a provider only appears if its client id/secret are set. Signing in with a provider auto-provisions a confirmed account; Profile → Connected accounts links and unlinks providers, with a guard against unlinking your only way back in. See Add an OAuth provider.
Cookie vs Bearer
The default is a hardened cookie scheme: HttpOnly, SameSite=Strict, Secure, and API endpoints return 401/403 rather than redirecting. A Bearer scheme activates by setting Auth:Scheme=Bearer — the access token is held in memory by the client and the refresh token is an HttpOnly cookie.
Never localStorage
Tokens are never placed in localStorage/sessionStorage — that's XSS-fatal. The cookie (or in-memory + httpOnly refresh cookie) handles it.
Access control is covered separately in Authorization.