Agora

Reference

The full defineConfig option tables for server and client.

Server — defineConfig (@adonis-agora/authkit-server)

AuthServerConfigInput:

OptionTypeDefaultNotes
issuerstringPublic provider URL; must end with mountPath.
adapterAdapterFactoryStorage adapter, e.g. adapters.database({ connection }).
clientsClientConfig[]Internal/test use only. Create clients via the admin console, Admin API (node ace authkit:clients:create), or Dynamic Registration.
jwksJwksConfig{ source: 'managed' | 'jwks', algorithm?, rotationDays?, keys? }.
ttlTtlConfigsee belowToken/session lifetimes; accepts '15m', '30d', or seconds. Declaring this key locks the token_ttl setting.
globalRolesClaimstring'roles'Claim name where global roles are emitted.
resolveTokenRoles(account, ctx) => string[] | Promise<string[]>account.globalRoles ?? []The pluggable seam for role emission — see Customizing auth. Called at mint time for first-party clients (see firstPartyClients), on token-exchange, and on the admin-console gate; ctx carries { clientId?, activeOrg? }. This is what lets an external authority (typically @adonis-agora/authz) own roles instead of a column on the account model.
cookieKeysstring[][]Cookie signing keys.
observabilityObservabilityConfig{}{ metrics?, jsonRoutes?, dashboard? }.
accountStoreAccountStorePrimary identity contract; derives findAccount/verifyCredentials. AccountStore = CoreAccountStore & Partial<Mfa/Webauthn/ProviderIdentity capabilities>; narrow with supportsMfa/supportsPasskeys/supportsProviderIdentity. See Account Store.
patStorePatStoreOptional; required only for PAT flows.
mountPathstring'/oidc'Where the host kit mounts the OIDC routes.
routesboolean | AuthHostOptionsabsent (no auto-mount)Mount the host kit from the config instead of calling registerAuthHost in start/routes.ts. true mounts with config defaults, an object supplies structural defaults (accountRoutes, account, accountLoginUrl, mountPath). Calling registerAuthHost afterwards throws — see Host Kit.
accountHomestring'/account/security'Default destination for the account area: post-login at /account/login (without return_to), e-mail confirmations, and non-admin redirects away from the console. Point it at your app's home to land users straight in the product.
renderAuthHostRendereredgeRendererinertiaRenderer to render the screens as Inertia pages, or edgeRenderer for the bundled Edge templates.
interactionRecovery{ mode?: 'screen' | 'redirect'; redirectTo?: string }{ mode: 'screen' }What happens when the OIDC interaction session is lost or expired: render the themeable session-expired screen, or 302 to the login. See Host Kit.
brandingBrandingConfigPer-client theming. Its firstParty list is also read as a fallback allowlist for the authorization claims, but prefer firstPartyClients for that — an authorization decision should not live in a theming block.
firstPartyClientsstring[]— (no allowlist)Which clients receive the authorization claims (<globalRolesClaim>, org_id, org_slug, org_role). Omit it and every registered client is first-party — the claims are still gated by client registration and by the client asking for scope=roles. Declare it to restrict them to your own apps; an explicitly empty list means nobody. See Customizing auth.
socialAuthSocialConfig{ providers: string[] }; opt-in social login.
patIntrospectionSecretstringShared secret authenticating PAT introspection.
rateLimitRateLimitConfigInputdisabledOpt-in anti-brute-force throttles. Declaring this key locks the rate_limit runtime setting — see Config locks. Leave it out to let the console own the buckets.
lockoutLockoutConfigInputenabledProgressive per-email lockout. store is infra. Declaring this key locks the lockout runtime setting. See Account Lockout.
mailMailHooksPluggable email hooks: onPasswordReset, onEmailVerification, onMagicLink, onSudoLink, onNewDeviceLogin, onOrgInvitation, onEmailChangeConfirm, onEmailChangeNotice, onOtpUnlock, onSecurityNotice, onAccountExpirationWarning, plus from and origin. Every hook is optional — without one the host kit sends its own branded, translated email. See Security — Mail hooks.
sudo{ methods?: SudoMethod[] }derived from the rest of the configThe identity-confirmation methods offered on /account/confirm. Omitting it derives a satisfiable list; declaring it turns derivation off and the list is taken literally. Declaring sudo.methods locks the sudoMethods route option. See Console session & sudo.
auditAuditSinkno-opBest-effort audit sink.
eventsEventsConfigInput{ onEvent?, webhook? } — observe every audit event in-process or via an HMAC-signed webhook. See Events & Webhooks.
mfaIssuerstring'AuthKit'TOTP issuer label shown in authenticator apps.
webauthnWebauthnConfigInputderived from issuerPasskey RP params. See WebAuthn.
i18nI18nConfigEnglish (en); pt-BR built inHost-kit screen translations. See Internationalization.
dynamicRegistrationDynamicRegistrationConfigInputdisabledRFC 7591/7592. See Dynamic Registration.
adminAdminConfigInputdisabledThe /admin console: { enabled, roles?, impersonation? }. impersonation: false unregisters the RFC 8693 grant outright and 404s the console panel — see Impersonation. Declaring this key locks the admin_impersonation setting and the admin route option (the prefix stays overridable). See Admin Console.
adminApitrue | { prefix?: string }disabledThe Admin REST API (API-key auth). true mounts at the default /api/authkit/v1; { prefix: '/custom/path' } overrides it (normalised: leading /, no trailing slash). Must match apiPrefix in the SDK's remote driver. Declaring this key locks the adminApi route option. See Admin REST API.
deviceFlow{ enabled: boolean }disabledDevice Authorization Grant (RFC 8628). See Device Flow.
dpop{ enabled: boolean }disabledDPoP sender-constrained tokens (RFC 9449). See Security.
par{ enabled: boolean; requirePushedAuthorizationRequests?: boolean }disabledPushed Authorization Requests (RFC 9126). See Security.
stepUp{ acrValues?: string[]; mfaAcr?: string }mfaAcr: 'urn:authkit:mfa'Step-up auth via acr_values. See Security.
trustedDevicesTrustedDevicesConfigInputenabled, 30 daysSkip MFA on a trusted device via an encrypted cookie. Declaring this key locks the trusted_devices setting. Step-up authentication always ignores the cookie. See MFA.
uploads{ avatars?: { disk?: string; directory?: string; maxSizeMb?: number } }app's default drive disk, authkit/avatars, 5MBAvatar upload via the app's @adonisjs/drive; degrades to URL input when drive is absent. See Host Kit.
passwordlessPasswordlessConfigInputall disabledMagic-link email login, passkey-first login, and password-free public sign-up. See Passwordless.
authMethodsAuthMethodsConfigInput{}Pin login methods in the file. Each field you declare wins over the auth_methods runtime setting and the console shows it read-only. Declaring this key locks the auth_methods setting. See Config locks.
loginLoginConfigInputall offLogin policy: requireVerifiedEmail (capability-probed) and otp (six-digit email codes — see Passwordless). Declaring login.requireVerifiedEmail locks the require_verified_email setting.
registration{ enabled?: boolean }{ enabled: true }Allow public sign-up. Declaring this key locks the registration setting — the console can no longer open or close sign-up. Leave it out to keep that switch in the console.
accessTokensAccessTokensConfig{ format: 'opaque' }JWT access tokens (RFC 9068) and per-resource config. See Security.
botProtectionBotProtectionConfigInputdisabledPluggable CAPTCHA/challenge for login, signup, reset; the host supplies verify. Fail-safe: a verify error or timeout lets the request through. Declaring this key locks the bot_protection setting. See Security.
notificationsRemoved. New-device and new-IP email alerts are managed via the notifications runtime setting (default: both on). See Runtime Settings and Security.
resolveGeo(ip: string) => Promise<string | null>Pluggable IP → location lookup for session context. See Admin Console.
organizationsOrganizationsConfigInputauto (on when the three org tables exist)Multi-tenancy. Declaring this key locks the organizations_policy setting. See Organizations.
schema{ autoManage?: boolean; connection?: string }{ autoManage: true }Auto-creation of the eight tables AuthKit owns. autoManage: false hands you the job — call ensureAuthkitSchema(db) from a migration. See Runtime Settings — Schema.
accountLifecycle{ durable?: boolean }{ durable: false }durable: true enqueues account deletion and export as durable workflows instead of running the cascade in-process. See Compliance — Durable workflows.
adonisAuth{ guard: string }absentOpt-in @adonisjs/auth integration: the account console's login/logout also drive ctx.auth.use(guard), so middleware.auth(), ctx.auth.user and the Bouncer work natively. Pair with authkitUserProvider in config/auth.ts. See AdonisJS Auth integration.

Ten of the options above are policy, and declaring one in defineConfig locks the matching runtime setting: registration, authMethods, login.requireVerifiedEmail, lockout, rateLimit, trustedDevices, botProtection, organizations, admin.impersonation and ttl. A locked key reads back as null, writes from the console and the Admin API fail with 423 Locked, and the console renders the control disabled. Five more — social, rateLimit, sudo.methods, admin and adminApi — lock the matching registerAuthHost argument the same way. Read Config locks before you decide where a policy belongs.

Watch the keys whose config type carries only infrastructure: declaring lockout: { store: 'redis' }, rateLimit, trustedDevices or organizations for plumbing reasons still locks the whole setting key, freezing its policy at the library defaults rather than at anything you wrote.

ttl defaults

FieldDefault
accessToken900 (15m)
refreshToken2592000 (30d)
idToken900 (15m)
session604800 (7d)

ClientConfig

FieldTypeNotes
clientIdstring
clientSecretstring?Omit for public clients.
redirectUrisstring[]Allowed authorization redirect URIs.
postLogoutRedirectUrisstring[]?For RP-initiated logout.
grantsstring[]?e.g. authorization_code, refresh_token, urn:ietf:params:oauth:grant-type:token-exchange.
tokenEndpointAuthMethod'client_secret_basic' | 'client_secret_post' | 'none''none' for public/SPA + PKCE.

RateLimitConfigInput

Infrastructure fields only. Bucket policy (login, introspection) is managed via the rate_limit runtime setting.

FieldTypeDefault
enabledbooleanfalse
storestring?host default store

Client — defineConfig (@adonis-agora/authkit-client)

ClientConfigInput:

OptionTypeDefaultNotes
issuerstringIdP issuer URL.
clientIdstringThis client's id.
clientSecretstring?For confidential clients.
redirectUristringThis client's callback URI.
resolverResolverFactoryresolvers.jwt(...) or resolvers.pat(...).
resolveUser(identity, ctx) => Promise<unknown>Map the IdP identity onto your own user. lucidMirror(...) is the ready-made implementation for a Lucid model — see Client.
sessionKeystring'authkit'Session key for the token set.
scopesstring[]['openid','profile','email','offline_access','roles']Requested scopes. Keep offline_access — without it the IdP issues no refresh token, and impersonation breaks the moment the admin's access token expires.
globalRolesClaimstring'roles'Claim to read global roles from.
backchannelLogoutBackchannelLogoutInputThe batteries-included back-channel logout path: { store } derives the callback, persists revocations, and pairs with BackchannelRevocationMiddleware. See Back-Channel Logout.
onBackchannelLogoutBackchannelLogoutCallbackInvoked with { sid, sub } on a valid logout token. Runs after the backchannelLogout store when both are set.
sessionIndexSessionIndexMaps OP sid/sub to local session ids — the manual alternative to backchannelLogout: { store }.
resilienceResiliencePolicyOptional policy wrapped around the outbound HTTP calls to the IdP (discovery + token endpoints). Pass the result of wrap(...) from @adonis-agora/resilience; typed structurally, so the client never imports that package.

Resolver factories

FactoryConfigNotes
resolvers.jwt{ tokenSource?, jwksUri? }Local JWKS validation; tokenSource defaults to 'session', jwksUri to ${issuer}/jwks.
resolvers.pat{ introspectionUrl, introspectionSecret }Validates PATs via the IdP introspection endpoint.
resolvers.opaque{ tokenSource?, introspectionUrl?, cacheTtlMs? }Per-request introspection of opaque access tokens (immediate revocation). Requires a confidential client.

Route registration

ExportPurpose
registerOidcClient(router, options)Registers /auth/login, the callback, /auth/logout and the back-channel endpoint in one call, with PKCE, state, and role-based post-login redirects. The path most relying parties want — see Client.
authkitClientGuard / AuthkitClientGuard@adonisjs/auth guard backed by the AuthKit session, so ctx.auth.user and middleware.auth() work natively. See AdonisJS Auth integration.
getAuthkit(ctx)Read the request's Authenticator without going through the container.
AuthkitContextMiddlewarePopulates the per-request identity.
lucidMirror(options)A resolveUser that mirrors the IdP identity into a Lucid model.
createUserinfoResolver(options)Builds a resolveUser that fetches the OP's userinfo endpoint.
conventionEndpoints(issuer)The endpoint map by convention, skipping discovery.
lucidRevocationStore / BackchannelRevocationMiddleware / DEFAULT_REVOCATION_TABLEThe batteries-included back-channel logout path.

Login primitives

Use these only when registerOidcClient cannot express your flow.

ExportPurpose
generatePkce()Build a PKCE { verifier, challenge, method: 'S256' }.
buildAuthorizeUrl(params)${issuer}/auth authorization URL.
exchangeCode(params)Swap an authorization code for a TokenSet.
refreshTokens(params)grant_type=refresh_token refresh (handles rotation). See Refresh Tokens.
exchangeToken(params)RFC 8693 token-exchange (impersonation).
buildEndSessionUrl(params)${issuer}/session/end RP-initiated logout URL.

SDK — createAuthkit (@adonis-agora/authkit-sdk)

createAuthkit(options): Promise<Authkit> builds the backend SDK.

ExportPurpose
createAuthkit({ mode: 'remote', baseUrl, apiKey, apiPrefix?, fetchImpl? })HTTP driver over the Admin REST API. apiPrefix defaults to '/api/authkit/v1'; override when the server uses a custom adminApi.prefix.
createAuthkit({ mode: 'embedded', app })In-process driver resolving server services from the AdonisJS container.
createRemoteAuthkit(options)The remote driver directly, when you already know you want HTTP and would rather skip the mode discriminator.
createEmbeddedAuthkit(options)The embedded driver directly.
AuthkitApiErrorError thrown by the remote driver (status, code, message).

See the SDK guide for the full method table.

Runtime Settings

An optional, capability-probed mechanism for persisting configuration at runtime in the auth_settings table. The table is detected on first access; all operations degrade gracefully when it is absent (fail-safe).

auth_settings schema

CREATE TABLE auth_settings (
  key        TEXT PRIMARY KEY,
  value      TEXT NOT NULL,        -- JSON
  updated_at TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP,
  updated_by TEXT                  -- nullable account id of the admin
);

Create the table with a migration of your own. AuthKit never creates it automatically — it is an opt-in capability.

RuntimeSettings

Class from @adonis-agora/authkit-server (internal, used by the admin console and API controllers). Accepts a Lucid Database instance and an optional ttlMs (default 15_000 — 15 s). Implements SettingsCapability.

MethodNotes
getSetting(key)Returns unknown | null. Null = table absent or key not found. Cached with TTL.
setSetting(key, value, updatedBy?)Upsert. Invalidates cache. No-op when the table is absent.
deleteSetting(key)Delete. Invalidates cache. No-op when the table is absent.
listSettings()Returns SettingRow[]. No cache (low-frequency). Empty array when the table is absent.
isTablePresent()Returns boolean. Result is memoised (probed once per instance).
invalidate(key?)Manually clear the in-memory cache (all keys when called without argument).

SettingsCapability and supportsSettings

import { supportsSettings } from '@adonis-agora/authkit-server'

if (supportsSettings(store)) {
  const raw = await store.getSetting('bot_protection')
}

supportsSettings(obj) is a type guard that returns true when obj exposes a getSetting function (i.e. implements SettingsCapability).

Known setting keys

Every key below is capability-probed: if the auth_settings table is absent, it falls back to the lib default (fail-safe). Precedence has two cases. When defineConfig does not declare the matching field, the persisted setting wins over the lib default. When it does, the key is locked — getSetting reads back null so the config value stands, and writes fail with 423 Locked. See Config locks for the ten lockable keys, and Runtime Settings for the canonical guide, the CLI, and migration from static config.

KeyShapeLib defaultNotes
bot_protection{ enabled: boolean; on?: ('login'|'signup'|'reset')[] }{ enabled: false }Runtime CAPTCHA toggle. See Security — Runtime toggle.
registration{ enabled: boolean }{ enabled: true }Open or close public sign-up. Overrides the static registration.enabled in defineConfig. See Security — Registration toggle.
require_verified_email{ enabled: boolean; graceDays?: number }{ enabled: false, graceDays: 0 }Block unverified accounts. graceDays allows newly-registered accounts to log in for N days without verifying. Capability-probed (isEmailVerified). See Compliance — Verified email gate.
maintenance_mode{ enabled: boolean; message?: string }{ enabled: false }Block login/sign-up/forgot for non-admins. Admin API escape hatch. See Security — Maintenance mode.
auth_methods{ password?: boolean; magicLink?: boolean; passkey?: boolean; passkeyAutofill?: boolean; social?: string[]; forgotPassword?: boolean }config/capability defaultsFilter login methods at runtime. passkeyAutofill: WebAuthn conditional mediation (default true when passkey on). forgotPassword auto-off when password off. social intersected with static providers. Fail-safe all-off reverts to defaults. See Security — Authentication methods.
email_change{ enabled?: boolean; ttlHours?: number; requirePassword?: boolean }{ enabled: true, ttlHours: 24, requirePassword: true }Verified email-change flow. See Compliance — Email change.
security_notifications{ enabled?: boolean; kinds?: string[] }{ enabled: true, kinds: [all 6] }Security-event emails. kinds: password_changed, mfa_enabled, mfa_disabled, passkey_added, passkey_removed, email_changed. See Compliance — Security notifications.
password_history{ enabled?: boolean; count?: number }{ enabled: false, count: 5 }Reuse prevention. Requires auth_password_history table. See Passwords — History.
password_expiration{ enabled?: boolean; maxAgeDays?: number }{ enabled: false, maxAgeDays: 90 }Force password rotation. Requires password_changed_at column. See Passwords — Expiration.
session_policy{ rememberEnabled?: boolean; rememberDays?: number; defaultSessionHours?: number; singleSession?: boolean; idleTimeoutMinutes?: number }{ rememberEnabled: true, rememberDays: 30, defaultSessionHours: 168, singleSession: false, idleTimeoutMinutes: 0 }Session duration and behaviour. Idle timeout applies to account console only (not OIDC tokens).
lockout{ enabled?: boolean; maxAttempts?: number; windowSec?: number; baseLockoutSec?: number; maxLockoutSec?: number }{ enabled: true, maxAttempts: 5, windowSec: 900, baseLockoutSec: 60, maxLockoutSec: 3600 }Per-email lockout policy. store stays in config (infra).
rate_limit{ login?: { points, duration }; introspection?: { points, duration } }login: { points: 10, duration: '1 min' }; introspection: { points: 60, duration: '1 min' }Rate-limit bucket policy. Limitation: route throttle middleware uses boot-time values; only lockout-side is dynamic.
password_policy{ minLength?: number; requireUppercase?: boolean; requireLowercase?: boolean; requireNumbers?: boolean; requireSymbols?: boolean; checkPwned?: boolean; blockCommon?: boolean }{ minLength: 8, checkPwned: false, blockCommon: true, rest false }Password complexity, HIBP check, and offline common-password block (~10k list). See Passwords.
notifications{ newLoginEmail?: boolean; newDeviceEmail?: boolean }{ newLoginEmail: true, newDeviceEmail: true }New-IP and new-device email alerts.
trusted_devices{ enabled?: boolean; days?: number }{ enabled: true, days: 30 }MFA skip via encrypted cookie. secrets stays in config (infra).
token_ttl{ accessTokenSec?: number; idTokenSec?: number; refreshTokenSec?: number }{ accessTokenSec: 900, idTokenSec: 900, refreshTokenSec: 2592000 }Token lifetimes (seconds). Takes effect immediately via holder. Session TTL is in session_policy.
admin_impersonation{ enabled?: boolean }{ enabled: false }Show impersonation panel in admin console.
organizations_policy{ allowSelfCreate?: boolean; invitationTtlHours?: number; roles?: string[] }{ allowSelfCreate: false, invitationTtlHours: 168, roles: ['owner','admin','member'] }Org policies. owner is always preserved.
sudo_mode{ enabled?: boolean; graceMinutes?: number }{ enabled: true, graceMinutes: 15 }Re-authentication gate for sensitive account actions. graceMinutes: 0 prompts on every action. The grace is bound to the account that earned it, so switching accounts always re-prompts. See Console session & sudo.
otp_lockout{ enabled?: boolean; maxAttempts?: number; unlockTtlHours?: number }{ enabled: true, maxAttempts: 5, unlockTtlHours: 24 }Lock TOTP/recovery after N failures; the account unlocks itself through a single-use emailed link (onOtpUnlock). Requires @adonisjs/limiter. See Security — OTP lockout.
account_expiration{ enabled?: boolean; inactiveDays?: number; warnDays?: number }{ enabled: false, inactiveDays: 365, warnDays: 14 }Block inactive accounts. Last activity = last login.success in audit. Warn via onAccountExpirationWarning({ email, expiresInDays }). Scan via authkit:accounts:expire-scan. Requires a queryable audit sink. See Compliance — Account expiration.
roles_catalog{ roles: { name: string; description?: string }[] }{ roles: [{ name: 'ADMIN', … }] }The catalogue of assignable global roles. It turns the free-text role field on the console's user page into checkboxes. ADMIN is always merged back in — it is the console's own gate, so it can never be catalogued away. Entries with an empty or non-string name are dropped silently, and the result is sorted by name. Resolves org-scoped first, then global, then the default.
key_rotation{ enabled?: boolean; maxAgeDays?: number; keep?: number }{ enabled: false, maxAgeDays: 90, keep: 2 }Automatic signing-key rotation for a managed keystore: rotate once the active key is older than maxAgeDays, retaining keep previous keys so tokens signed before the rotation still verify. Surfaced by the console's key page and by GET {adminApi}/keys. See Security — Signing key rotation.

Ace commands

Commands provided by @adonis-agora/authkit-server:

CommandNotes
node ace authkit:doctorValidate the config and peer dependencies; emits findings with ok/warn/error levels. Includes checkSettings (bot_protection orphan, require_verified_email capability) and checkClients (informational: adapter volatility warning).
node ace authkit:ejectCopy the bundled host-kit controllers/pages into your project for customization.
node ace authkit:users:import --file <path> [--dry-run]Bulk-import users from a JSON array or NDJSON file, preserving hashes as-is for lazy rehash on login.
node ace authkit:keys:rotate [--keep=N] [--retire] [--dry-run]Rotate signing keys in a managed keystore file; keeps a grace-period window of N previous keys (default 2).
node ace authkit:clients:create --redirect-uri=<uri> [--client-id] [--public] [--grant] [--post-logout-uri] [--backchannel-logout-uri] [--json]Create an OIDC client in the adapter/DB at runtime. For confidential clients a secret is generated and printed once — save it immediately. See below.
node ace authkit:settings:list [--json]List all runtime settings currently persisted in the auth_settings table.
node ace authkit:settings:get <key> [--json]Get a specific setting by key. Prints null if the key is not set (lib default applies).
node ace authkit:settings:set <key> <json> [--json]Upsert a setting. Validates shape for known keys. Audits settings.updated with updatedBy: 'cli'.
node ace authkit:settings:unset <key> [--json]Delete a setting (reset to lib default). Audits settings.updated.
node ace authkit:accounts:expire-scan [--warn] [--dry-run] [--json]Scan for expired/expiring accounts. --warn sends mail.onAccountExpirationWarning (deduped via audit). --dry-run prints counts without writing. --json outputs { expired, warned, skipped }. See Compliance — Account expiration.

authkit:doctor — the full check list

The doctor runs thirty-one checks and prints each one at ok, warn or error. Most are informational: they tell you which optional capability is actually reachable, given the config, the account store and the tables that exist. A check stays silent when the feature it covers is switched off — an opt-in feature you never enabled is not a finding.

CheckWhat it looks at
checkConfigResolvesconfig('authkit') resolves at all.
checkIssuerissuer is a valid URL and its pathname matches mountPath.
checkClientsNo static clients in the config — clients are runtime-only, via the console or the Admin API.
checkAdapterVolatilityThe adapter persists. Because clients live only at runtime, a volatile adapter (in-memory, Redis without persistence) silently loses them on restart.
checkAccountStoreThe store is present, and which capabilities it implements.
checkSession@adonisjs/session is configured; warns about the cookie store with large token sets.
checkShieldThe CSRF exceptions Shield needs for mountPath.
checkAlly@adonisjs/ally is present when social login is configured.
checkOtpLockoutOTP lockout is enabled but @adonisjs/limiter is missing, which makes it a no-op.
checkSudoModeReports the effective sudo-mode state.
checkRateLimitrateLimit is on but @adonisjs/limiter is missing.
checkAdminadmin.enabled without roles; reports the active UI mode.
checkRequireVerifiedEmailThe gate is on but the store cannot answer isEmailVerified.
checkBotProtectionWhich actions the challenge covers, and a reminder of the fail-safe semantics.
checkWebauthnThe WebAuthn rpId matches the issuer host.
checkPasswordPolicyThe policy shape is valid; reports whether the breach check is on.
checkJwksRotation state for a managed keystore; warns when managed without a store (no real rotation).
checkAccessTokensThe access-token format; in JWT mode, reminds you the JWKS must be persisted so relying parties keep validating across restarts.
checkOrganizationsOrganizations are enabled in the config but the store lacks the capability.
checkSettingsThe auth_settings table's presence; flags an orphan bot_protection row that has no verify behind it.
checkAuthMethodsSettingThe persisted auth_methods value has a usable shape — notably, that it does not switch every method off.
checkEmailChangeThe store supports the verified email-change flow.
checkSecurityNotificationsMail is configured and the store supports the security capability.
checkPasswordPepperReports how the password pepper is configured, and nudges a bare string toward the [new, old] array form that allows rotation without downtime.
checkPasswordHistoryThe auth_password_history table exists when reuse prevention is on.
checkPasswordExpirationThe password_changed_at column exists when expiration is on.
checkSessionPolicyInternally inconsistent values — e.g. an idle timeout longer than the session itself, which can never fire.
checkRolesCatalogWarns when admin.roles names a role outside the catalogue, which would leave the console gate unreachable.
checkAccountExpirationThe audit sink can be queried (otherwise the feature is unavailable) and the setting's fields cohere.
checkPasskeyAutofillConditional mediation can actually be offered — it never appears without WebAuthn configured.
checkFirstPartyClientsWhether a first-party allowlist is declared. Without one, every registered client that asks for scope=roles receives the roles and organization claims.

authkit:users:import

See Passwords & Migration for the file format and field list.

authkit:keys:rotate

See Security — Signing key rotation for the flag reference and rotation strategy.

authkit:clients:create

Creates an OIDC client in the adapter/DB at runtime via AdminClientsService — the same path used by the admin console and Dynamic Registration (RFC 7591). No redeploy needed.

# Public SPA client
node ace authkit:clients:create \
  --client-id=acme-web \
  --redirect-uri=https://web.acme.com/auth/callback \
  --public

# Confidential client (secret printed once)
node ace authkit:clients:create \
  --client-id=acme-api \
  --redirect-uri=https://api.acme.com/cb \
  --grant=authorization_code \
  --grant=refresh_token

# Machine-readable JSON output
node ace authkit:clients:create \
  --redirect-uri=https://app.acme.com/cb \
  --json

Flags:

FlagNotes
--redirect-uri=<uri>Allowed callback URI (repeatable). Required.
--client-id=<id>Desired client_id. Omit to generate a random UUID.
--publicCreate a public client (no secret; token_endpoint_auth_method=none). Default: confidential.
--grant=<type>Grant type (repeatable). Default: authorization_code + refresh_token.
--post-logout-uri=<uri>Post-logout redirect URI (repeatable).
--backchannel-logout-uri=<uri>OIDC Back-Channel Logout endpoint of the RP.
--jsonPrint the result as JSON (includes clientId and clientSecret for confidential clients).

For confidential clients a clientSecret is generated and printed exactly once — store it immediately. The admin console and Admin API are alternatives when you prefer a browser or HTTP interface.

Server backend helpers — @adonis-agora/authkit-server

Helpers for use inside AdonisJS controllers, middleware, and route callbacks.

Console session

ExportPurpose
getAccountId(ctx)Returns string | null — the account the console session currently acts as. During an impersonation session this is the target.
realAccountId(ctx)Returns string | null — the human behind the session. Outside impersonation it equals getAccountId; during impersonation it stays the admin. Authorize with this one; getAccountId answers "whose data am I looking at", not "who is allowed to do this". See Impersonation.
hasAccountSession(ctx)Returns booleantrue when the console session is present.
consoleLoginUrl(returnTo?)The login URL with an optional return_to, honouring an accountLoginUrl override.
ACCOUNT_SESSION_KEYRaw session key. Prefer getAccountId/hasAccountSession.

See Console session & sudo mode for recipes.

Sudo mode (step-up authentication)

ExportPurpose
requireSudo(ctx, settings)Returns true when the caller already holds sudo, and otherwise returns a redirect to the confirmation screen with a return_to. Guard with if (gate !== true) return gate. Both arguments are required: settings is a SettingsCapability or null, and null means "no runtime settings here", so SUDO_MODE_DEFAULTS applies. Fail-safe — a settings error lets the request through.
isSudoActive(ctx, graceMinutes)Pure boolean check — true when the step-up timestamp is within the grace window and belongs to the account currently signed in.
markSudo(ctx)Stamps the step-up timestamp, bound to the current account. Deprecated as a way to grant sudo — it records no sudo.confirmed audit event, no remembered method and no redirect. Use completeSudo(sudoContextFrom(ctx), methodId) instead.
SUDO_SESSION_KEYRaw session key for the timestamp.
SUDO_ACCOUNT_SESSION_KEYRaw session key for the account the grace was earned by — checked before the grace window, so a sudo grant cannot survive a switch to another account.
SUDO_MODE_DEFAULTS{ enabled: true, graceMinutes: 15 }
resolveEffectiveSudoMode(settings)Reads the sudo_mode setting from a SettingsCapability, with fail-safe fallback.

Sudo methods (the confirmation SPI)

The methods offered on the confirmation screen are pluggable. Read Console session & sudo mode for the full guide.

ExportPurpose
sudoMethodsThe built-in method factories: password(), passkey(), magicLink(), oidcStepUp().
completeSudo(context)Grant sudo from your own handler. Required for oidcStepUp(), which registers no routes — your callback validates the grant, so your callback has to grant the sudo. Doing it with markSudo instead loses the sudo.confirmed audit event, the remembered method, and the return_to redirect.
failSudo(context, reason)Record a failed confirmation attempt.
sudoContextFrom(ctx)Build the SudoContext the two functions above take. Use it — assembling the context by hand means validating return_to by hand, which is an open redirect waiting to happen.
LAST_METHOD_SESSION_KEYRaw session key for the last method used successfully, which is promoted to the top of the screen.
SudoMethod / SudoContext / SudoMethodDescriptor / SudoRouteHelpersThe SPI types for writing your own method.

Config locks

ExportPurpose
SettingLockedErrorThrown by setSetting/deleteSetting for a key locked by defineConfig. Carries code: 'E_SETTING_LOCKED' and the key; the console and Admin API surface it as 423 Locked.
isSettingLocked(key)Is this key locked?
lockedSettingKeys()Snapshot of the locked keys — what a custom settings UI reads to render controls as disabled.
deriveLockedSettingKeys(config)Derives the locked keys from a raw config input.
setLockedSettingKeys(keys)Installs the lock set. The provider calls this once at boot; a host normally never does.
resetLockedSettingKeys()Clears the locks — for tests.
POLICY_ROUTE_OPTIONS / PolicyRouteOptionThe five registerAuthHost options that are policy rather than structure.

See Config locks.

@adonisjs/auth integration

ExportPurpose
authkitUserProvider(...)User provider for config/auth.ts's sessionGuard(), backed by AuthKit's own account store. Pair with adonisAuth: { guard }.
oidcRpGuard(...) / OidcRpGuardGuard for a relying party: the identity comes from the session the OIDC callback wrote, so ctx.auth.user works without the RP authenticating anyone itself.
OidcRpGuardOptions / OidcRpGuardEventsIts option and event types.

See AdonisJS Auth integration.

Trusted devices

ExportPurpose
resolveTrustedDevices(input)Resolve the config into its effective form.
isTrustedDeviceValid(payload, ...)Is a decoded cookie payload still valid for this account?
buildTrustedDevicePayload(...)Build the payload to store in the cookie after a successful MFA challenge.
TRUSTED_DEVICE_COOKIEThe cookie name.

Step-up authentication always ignores the cookie — the whole point of a step-up is that a past decision does not answer for it. See MFA — Trusted devices.

Durable account lifecycle

Published from @adonis-agora/authkit-server/durable, and only relevant with accountLifecycle: { durable: true }. See Compliance — Durable workflows.

ExportPurpose
defineAccountDeletionWorkflow(...) / defineAccountExportWorkflow(...)Register the two workflows with your app's workflow engine.
enqueueAccountDeletion(...) / enqueueAccountExport(...)Enqueue a run.
enqueueDeletionVia(...)Enqueue a deletion through a specific engine instance.
resolveWorkflowEngine(...)Locate the app's workflow engine.

Impersonation (relying-party glue)

ExportPurpose
rememberAccessToken(ctx, token)Store the admin's access token so it can be exchanged later.
rememberRefreshToken(ctx, token)Store the refresh token. Required — without it, impersonation dies when the admin's access token expires. Needs offline_access in the RP's requested scopes.
refreshAccessToken(ctx, ...)Renew the stored access token from the refresh token.
startImpersonation(params)Exchange the admin's token for a token representing the target (RFC 8693).
impersonationState(ctx)The current ImpersonationState, or none.
stopImpersonation(ctx)Drop back to the admin's own session.

See Impersonation.

Client helpers — @adonis-agora/authkit-client

Additional exports beyond the resolver factories:

ExportPurpose
verifyJwtAccessToken(token, options)Verify a JWT AT (RFC 9068) locally against the IdP's JWKS. See Client.
clearJwksCache()Clear the in-process JWKS cache (useful in tests).

Account Self-Service API — /account/api/*

Session-authenticated JSON API served by @adonis-agora/authkit-server. Mounted automatically when the account console is enabled (always on by default with registerAuthHost). Mutating routes require an X-CSRF-TOKEN header. Sensitive actions require an active sudo session — the server returns 403 { error: { code: 'sudo_required' } } when the grace period has expired.

MethodPathNotes
GET/account/api/meProfile + capability flags (capabilities.*) + sudo state
GET/account/api/securityActive sessions, MFA status, passkeys, pending email change
PATCH/account/api/profile{ name?, avatarUrl? } — update profile
POST/account/api/password{ currentPassword, newPassword } — sudo + current password required
POST/account/api/email-change{ newEmail, currentPassword? } — sudo required; obeys email_change setting
POST/account/api/email-change/cancelCancel pending email change
GET/account/api/sessions{ supported, sessions[] }
DELETE/account/api/sessions/:idRevoke one session
POST/account/api/sessions/revoke-othersRevoke all other OIDC sessions
POST/account/api/sessions/revoke-allSign out of all devices (including current session)
GET/account/api/apps{ supported, apps[] } — OAuth grants
DELETE/account/api/apps/:clientIdRevoke an app's grants
GET/account/api/mfa{ enabled, totp, passkeys, recovery }
GET/account/api/passkeys{ supported, passkeys[] }
DELETE/account/api/passkeys/:idRemove passkey — sudo required
GET/account/api/tokens{ supported, tokens[] } — Personal Access Tokens
POST/account/api/tokens{ name? } — create PAT (sudo required); secret returned once
DELETE/account/api/tokens/:idRevoke PAT — sudo required
GET/account/api/orgs{ supported, activeOrgId, orgs[] }
GET/account/api/orgs/invitations{ supported, invitations[] } — pending invitations
GET/account/api/orgs/:idOrg detail — requires membership

All routes are capability-probed: if the store doesn't support a feature, the response contains { supported: false } instead of an error. The TypeScript types for every response are exported from @adonis-agora/authkit-react (see below).

React SDK — @adonis-agora/authkit-react

Full export list. For usage and examples see React (Frontend), React Components, and Typed Client & TanStack Query.

Auth state

ExportNotes
useAuth(){ user, isAuthenticated, globalRoles, hasGlobalRole, hasAnyGlobalRole, hasAllGlobalRoles }, read from the authkit Inertia shared prop (or an AuthProvider above it). Never throws — a missing prop yields the unauthenticated state
AuthProvider / AuthContextInject auth state outside Inertia
AuthkitProviderConfigure URLs, endpoints, and the IdP mode
AuthkitConfigContext / useAuthkitConfig / resolveConfig / buildAuthUrl / DEFAULT_CONFIGThe configuration layer under AuthkitProvider
Authenticated / GuestGating components
CanPermissionPermission-gating component, backed by the can endpoint
useCan / checkCan / invalidateCanCacheThe hook, the bare check, and the cache reset behind CanPermission
hasGlobalRole / hasAnyGlobalRole / hasAllGlobalRolesPure global-role helpers

AuthKit authenticates and carries global roles. Per-application authorization — app-local roles and permissions — belongs to @adonis-agora/authz, and reaches React through useCan / CanPermission. There is no hasAppRole on ctx.auth and no app-role helper in this package.

Headless hooks

ExportNotes
useSignIn / useSignOutOIDC redirect
useUserAlias over useAuth
useProfile{ data, loading, error, actions: { update } }
useSessions{ data, loading, error, actions: { revoke, refetch } }
useAuthorizedApps{ data, loading, error, actions: { revoke } }
useOrganizations{ data, loading, error, activeOrgId, supported, actions }
useOrganization(orgId)Org detail + members
useSwitchOrganization{ activate(orgId), deactivate() }
useOrgInvitations{ data, loading, error, actions: { accept } }
usePasswordStrength(password, opts?){ score: 0–4, feedback }; heuristicScorer is the default scorer and can be swapped
usePasskeyAutofill(opts)WebAuthn conditional mediation
usePasskeyLogin(opts)Passkey sign-in for a custom login screen
usePasskeyAssertion(opts) / usePasskeyRegistration(opts)The assertion and registration ceremonies as hooks
useResource / jsonRequestThe generic JSON primitive every headless hook is built on

Passkeys — the three tiers

TierExport
ComponentPasskeyButton
HooksusePasskeyLogin, usePasskeyAssertion, usePasskeyRegistration, usePasskeyAutofill
FunctionsauthenticatePasskey, registerPasskey, submitPasskeyVerification, runPasskeyAssertion, runPasskeyRegistration, submitClassicForm, loadStartAuthentication, loadStartRegistration

Reach for the component on a stock login screen, the hook inside your own React screen, and the function when your screen owns its state machine. See React and Components.

Interaction URLs

ExportNotes
interactionUrlsTyped builders for the interaction endpoints
oauthRedirectUrlThe OAuth redirect URL builder
OTP_CODE_FIELDThe form field name the OTP step posts
InteractionUrls / InteractionPostStepTheir types

Typed client

ExportNotes
createAuthkitClient(opts?)Factory — returns AuthkitClient
AuthkitClientError{ status, code?, message, body, isUnauthorized }
AuthkitClientProviderReact context provider for the client
useAuthkitClient()Read the client from context
createAuthkitQueryClient()Pre-configured QueryClient (staleTime 30s, gcTime 5min, retry 1)

Query keys

ExportNotes
authkitKeys.admin.*Structured keys for all admin queries, including admin.keys()
authkitKeys.account.*Structured keys for all account queries
authkitKeys.admin.settings(orgId?)Settings key; without an orgId it is the global scope

Admin query hooks

useOverviewQueryOptions, useUsersQueryOptions, useUserQueryOptions, useUserSessionsQueryOptions, useSessionsQueryOptions, useClientsQueryOptions, useClientQueryOptions, useRolesQueryOptions, useOrgsQueryOptions, useOrgQueryOptions, useAuditQueryOptions, useSettingsQueryOptions, useImpersonationQueryOptions, useKeysQueryOptions.

Admin mutation hooks

useCreateUserMutationOptions, useUpdateUserMutationOptions, useDisableUserMutationOptions, useEnableUserMutationOptions, useResetPasswordMutationOptions, useDeleteUserMutationOptions, useRevokeUserSessionsMutationOptions, useRevokeAllSessionsMutationOptions, useCreateClientMutationOptions, useUpdateClientMutationOptions, useDeleteClientMutationOptions, useRegenerateClientSecretMutationOptions, useCreateRoleMutationOptions, useUpdateRoleMutationOptions, useDeleteRoleMutationOptions, useCreateOrgMutationOptions, useUpdateOrgMutationOptions, useDeleteOrgMutationOptions, useAddOrgMemberMutationOptions, useRemoveOrgMemberMutationOptions, useUpdateOrgMemberRoleMutationOptions, useCreateOrgInvitationMutationOptions, useRevokeOrgInvitationMutationOptions, useSetSettingMutationOptions, useRemoveSettingMutationOptions, useRotateKeysMutationOptions.

Account query hooks

useMeQueryOptions, useSecurityQueryOptions, useAccountSessionsQueryOptions, useAppsQueryOptions, useMfaQueryOptions, usePasskeysQueryOptions, useTokensQueryOptions, useAccountOrgsQueryOptions, useAccountOrgQueryOptions, useAccountOrgInvitationsQueryOptions.

Account mutation hooks

useUpdateProfileMutationOptions, useChangePasswordMutationOptions, useEmailChangeMutationOptions, useCancelEmailChangeMutationOptions, useRevokeSessionMutationOptions, useRevokeOtherSessionsMutationOptions, useAccountRevokeAllSessionsMutationOptions, useRevokeAppMutationOptions, useRemovePasskeyMutationOptions, useCreateTokenMutationOptions, useRevokeTokenMutationOptions.

On this page