Authentication and account security
Which Ory Kratos method backs which sign-in and account screen of the kit, the account security API (security overview, sessions, account deletion), and how to turn a method or a surface off.
Ory Kratos owns identities, credentials and sessions; the kit renders every screen and keeps its own users, organizations and roles. This guide maps the screens of the design to the Kratos method or the kit endpoint behind each, and says how to turn each one off. The Kratos files and variables are in infra/ory/kratos/README.md; who may call what is in the authorization guide.
Methods and screens
| Screen | Backed by | Kratos method |
|---|---|---|
| AUTH-01 sign-in, AUTH-02 sign-up | Kratos login and registration flows | password, code (sign-in by code), passkey, oidc |
| AUTH-06 two-factor step | Kratos login flow at aal2 | totp, webauthn, lookup_secret |
| ACC-02 email change | Kratos settings flow | profile (the change is synced to the kit by the settings hook) |
| ACC-03 password | Kratos settings flow | password |
| ACC-04 two-factor | Kratos settings flow, and GET /v1/me/security for the summary | totp, webauthn, passkey, lookup_secret |
| ACC-05 sessions | GET /v1/me/sessions, DELETE /v1/me/sessions/{sessionId}, DELETE /v1/me/sessions | — (Kratos' admin API) |
| ACC-06 connected accounts | Kratos settings flow | oidc |
| ACC-07 delete account | POST /v1/me/delete | — (Kratos' admin API) |
Every screen renders Kratos' own form nodes, filtered by the capabilities the API serves anonymously at GET /v1/auth/capabilities: the social buttons of the configured providers only, and the security key and passkey steps only while they are on. For those two, the web loads the script Kratos sends with the flow (Ory's WebAuthn script, with Kratos' integrity hash and nonce) and calls its trigger on the button (oryPasskeyLogin, oryWebAuthnLogin, oryPasskeyRegistration, ...); the script asks the browser for the credential and submits the form. The passkey autofill starts once the script has loaded. When the API does not answer, the screens offer email with a password or a code only. A person who set up a second factor must use it: session.whoami.required_aal is highest_available.
The account settings
The account settings (/<org>/settings/account) have one tab per screen, shown while its capability is on: Profile and Email always; Password with Password; Two-factor with any of Totp, WebAuthn, Passkeys or LookupSecrets; Sessions with SessionManagement; Connected accounts with at least one of OidcProviders; Delete account with AccountDeletion. A tab whose capability is off answers 404.
- Email, Password, Two-factor and Connected accounts render Kratos' settings flow, each tab only its method group: the Email tab shows the address alone and sends the names along unchanged; the Two-factor tab has one section per method on the same flow (the authenticator app's QR code and secret, security keys, passkeys, and the recovery codes, which are confirmed only once the person ticks that they saved them).
- Each tab starts its flow with itself as the return address. Kratos sends every settings flow to its one settings address (
/account), which sends the browser back to that tab with the flow. - A change in a session older than
privileged_session_max_age(15 minutes) makes Kratos ask the person to sign in again; the form follows it there and back. - Sessions lists the sessions from the API and signs out one or all others. Delete account asks for the email address and, while the person alone owns organizations, names them with a link to hand each over.
The account security API
Every endpoint is the signed-in person's own, under /v1/me, and needs a session (an API key is refused).
GET /v1/me/securityreturns the session's assurance level (aal1,aal2), the methods the person set up (password,totp,securityKeys,passkeys,recoveryCodes, and theconnectedAccountsproviders), and the capabilities on offer, for the ACC-04 summary.GET /v1/me/sessionslists the person's sessions from Kratos, the current one first, with the device and network address that signed in and the assurance level. The kit stores none.DELETE /v1/me/sessions/{sessionId}ends one other session; a session of someone else is not found (404), and the current one ends by signing out (409).DELETE /v1/me/sessionsends every session but the current one and says how many.
Ending sessions is logged with the user id, not audited: the audit log belongs to an organization, and a session belongs to the person.
Deleting an account
POST /v1/me/delete with { "confirmEmail": "..." }, the account's address typed again (any case), deletes the account:
- An organization the person is the only owner of must be handed over first: the answer is 409
ownership-transfer-requiredwith theorganizations(id, name, slug) to transfer on their settings page. Co-owned organizations do not block. - Each membership is removed and recorded as
member.account_deletedin that organization's audit log. - The kit's user row keeps no personal data: the address becomes
deleted-<id>@deleted.invalid, the names and the avatar go, the identity link is cut anddeleted_atis set. The row stays for the records that point at it (invitations sent, API keys created). - Kratos ends every session and deletes the identity.
All of it happens in one database transaction that commits after Kratos answered, so if Kratos refuses, nothing changed in the kit. A super-admin impersonating the person cannot delete the account (403).
Capabilities
Ory:Capabilities tells the API and the web what Kratos has enabled, since the web shows only what is on and the API refuses what is off. The API's appsettings.json mirrors the kit's kratos.yaml:
| Key | Default | Turns on |
|---|---|---|
Password, Code | on | Email and password; one-time codes |
Totp, WebAuthn, LookupSecrets | on | Authenticator apps, security keys and recovery codes as second factors |
Passkeys | on | Passkeys as a first factor |
OidcProviders | empty | The social sign-in providers on offer (google, github, microsoft) |
SessionManagement | on | GET/DELETE /v1/me/sessions |
AccountDeletion | on | POST /v1/me/delete |
An operation whose capability is off answers 501 capability-disabled, naming the capability.
Turning a method or a surface off
- A Kratos method (for example passkeys): set it off in
kratos.yaml(selfservice.methods.passkey.enabled: false, orSELFSERVICE_METHODS_PASSKEY_ENABLED=falsein one environment) and set the matchingOry:Capabilities:Passkeystofalse, so both agree. - Social sign-in: it is off in
kratos.yaml; an environment turns it on withSELFSERVICE_METHODS_OIDC_ENABLED=trueand the client id and secret of each provider it uses, and lists those providers inOry:Capabilities:OidcProviders(see the Kratos README). - A kit surface:
Ory:Capabilities:SessionManagementor:AccountDeletionset tofalseturns the endpoints off (501).
Run tools/kratos-validate.sh after changing kratos.yaml, and tools/helm-check.sh --sync to copy it into the chart.
Testing
FakeIdentityProvider (tests/Colden.Testing/Auth) is an identity server in memory: identities with their credentials and sessions, and a record of what the API revoked and deleted. The API's account security tests sign in with TestUserBuilder and replace IIdentityProvider with it; see the testing guide.