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

ScreenBacked byKratos method
AUTH-01 sign-in, AUTH-02 sign-upKratos login and registration flowspassword, code (sign-in by code), passkey, oidc
AUTH-06 two-factor stepKratos login flow at aal2totp, webauthn, lookup_secret
ACC-02 email changeKratos settings flowprofile (the change is synced to the kit by the settings hook)
ACC-03 passwordKratos settings flowpassword
ACC-04 two-factorKratos settings flow, and GET /v1/me/security for the summarytotp, webauthn, passkey, lookup_secret
ACC-05 sessionsGET /v1/me/sessions, DELETE /v1/me/sessions/{sessionId}, DELETE /v1/me/sessions— (Kratos' admin API)
ACC-06 connected accountsKratos settings flowoidc
ACC-07 delete accountPOST /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/security returns the session's assurance level (aal1, aal2), the methods the person set up (password, totp, securityKeys, passkeys, recoveryCodes, and the connectedAccounts providers), and the capabilities on offer, for the ACC-04 summary.
  • GET /v1/me/sessions lists 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/sessions ends 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:

  1. An organization the person is the only owner of must be handed over first: the answer is 409 ownership-transfer-required with the organizations (id, name, slug) to transfer on their settings page. Co-owned organizations do not block.
  2. Each membership is removed and recorded as member.account_deleted in that organization's audit log.
  3. 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 and deleted_at is set. The row stays for the records that point at it (invitations sent, API keys created).
  4. 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:

KeyDefaultTurns on
Password, CodeonEmail and password; one-time codes
Totp, WebAuthn, LookupSecretsonAuthenticator apps, security keys and recovery codes as second factors
PasskeysonPasskeys as a first factor
OidcProvidersemptyThe social sign-in providers on offer (google, github, microsoft)
SessionManagementonGET/DELETE /v1/me/sessions
AccountDeletiononPOST /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, or SELFSERVICE_METHODS_PASSKEY_ENABLED=false in one environment) and set the matching Ory:Capabilities:Passkeys to false, so both agree.
  • Social sign-in: it is off in kratos.yaml; an environment turns it on with SELFSERVICE_METHODS_OIDC_ENABLED=true and the client id and secret of each provider it uses, and lists those providers in Ory:Capabilities:OidcProviders (see the Kratos README).
  • A kit surface: Ory:Capabilities:SessionManagement or :AccountDeletion set to false turns 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.