Authentication
Truss provides a full authentication system powered by Ory Kratos. The dashboard gives you a GUI for managing users, sessions, MFA, social login providers, and security policies. Everything is also available via API and client SDKs.
Setup
Set these environment variables in apps/api/.env:
KRATOS_PUBLIC_URL=http://localhost:4433KRATOS_ADMIN_URL=http://localhost:4434KRATOS_ADMIN_TOKEN=your-admin-tokenTRUSS_AUTH_REQUIRED=trueWith TRUSS_AUTH_REQUIRED=true, the dashboard requires login. Set to false for local development without auth.
Optional configuration:
# Restrict registration to invited users onlyTRUSS_INVITE_ONLY=true
# Social/OIDC providers (comma-separated)KRATOS_OIDC_PROVIDERS=google,github,apple,microsoft
# Identity schema ID (defaults to "default")KRATOS_IDENTITY_SCHEMA_ID=defaultLogin Methods
Email + Password
The standard credential-based login flow. Truss uses Kratos API flows (not browser flows) to avoid CSRF issues when the frontend and backend are on different origins.
Dashboard: Authentication > Overview (login form)
Flow:
- Frontend calls
GET /api/auth/loginto initialize a Kratos login flow - User submits credentials via
POST /api/auth/login - Server stores the session token in an HttpOnly cookie (
truss_session) - Subsequent requests are authenticated via the cookie
# 1. Initialize login flowcurl http://localhost:8787/api/auth/login
# 2. Submit credentialscurl -X POST http://localhost:8787/api/auth/login \ -H "Content-Type: application/json" \ -d '{ "email": "user@example.com", "password": "securepassword123" }'TOTP MFA (Authenticator App)
Time-based one-time password MFA using apps like Google Authenticator or Authy. Users can set up, verify, and remove TOTP from the settings page.
Dashboard: Authentication > Settings (MFA section)
API Endpoints:
| Method | Path | Description |
|---|---|---|
GET | /api/auth/mfa/status | Get current MFA status (TOTP enabled, WebAuthn devices, recovery codes) |
POST | /api/auth/mfa/totp/setup | Start TOTP setup — returns QR code URI and secret |
POST | /api/auth/mfa/totp/verify | Verify TOTP code to complete setup |
DELETE | /api/auth/mfa/totp | Remove TOTP from the account |
// Check MFA statusconst status = await fetch(`${TRUSS_URL}/api/auth/mfa/status`, { credentials: "include",}).then(r => r.json());// { totp: true, webauthn: false, recovery_codes: true, devices: [] }
// Start TOTP setupconst setup = await fetch(`${TRUSS_URL}/api/auth/mfa/totp/setup`, { method: "POST", credentials: "include",}).then(r => r.json());// { totpUrl: "otpauth://totp/Truss:user@example.com?secret=...", secret: "JBSWY3DPEHPK3PXP" }
// Verify TOTP codeawait fetch(`${TRUSS_URL}/api/auth/mfa/totp/verify`, { method: "POST", credentials: "include", headers: { "Content-Type": "application/json" }, body: JSON.stringify({ totp_code: "123456" }),});
// Remove TOTPawait fetch(`${TRUSS_URL}/api/auth/mfa/totp`, { method: "DELETE", credentials: "include",});# Check MFA statuscurl http://localhost:8787/api/auth/mfa/status \ -H "Cookie: truss_session=your-session-token"
# Start TOTP setupcurl -X POST http://localhost:8787/api/auth/mfa/totp/setup \ -H "Cookie: truss_session=your-session-token"
# Verify TOTP codecurl -X POST http://localhost:8787/api/auth/mfa/totp/verify \ -H "Cookie: truss_session=your-session-token" \ -H "Content-Type: application/json" \ -d '{"totp_code": "123456"}'
# Remove TOTPcurl -X DELETE http://localhost:8787/api/auth/mfa/totp \ -H "Cookie: truss_session=your-session-token"WebAuthn MFA (Security Keys)
Hardware security key support (YubiKey, etc.) via the FIDO2/WebAuthn protocol. Setup, verification, and removal are handled through the settings flow.
Dashboard: Authentication > Settings (MFA section)
API Endpoints:
| Method | Path | Description |
|---|---|---|
POST | /api/auth/mfa/webauthn/setup | Start WebAuthn registration — returns credential creation options |
POST | /api/auth/mfa/webauthn/verify | Complete WebAuthn registration with attestation response |
DELETE | /api/auth/mfa/webauthn | Remove WebAuthn credential |
// Start WebAuthn setup — returns options for navigator.credentials.create()const options = await fetch(`${TRUSS_URL}/api/auth/mfa/webauthn/setup`, { method: "POST", credentials: "include",}).then(r => r.json());
// Browser handles the key interactionconst credential = await navigator.credentials.create({ publicKey: options.publicKey,});
// Complete registrationawait fetch(`${TRUSS_URL}/api/auth/mfa/webauthn/verify`, { method: "POST", credentials: "include", headers: { "Content-Type": "application/json" }, body: JSON.stringify({ webauthn_register_displayname: "My YubiKey", webauthn_register: JSON.stringify(credential), }),});
// Remove WebAuthn credentialawait fetch(`${TRUSS_URL}/api/auth/mfa/webauthn`, { method: "DELETE", credentials: "include",});# Start WebAuthn setupcurl -X POST http://localhost:8787/api/auth/mfa/webauthn/setup \ -H "Cookie: truss_session=your-session-token"
# Remove WebAuthn credentialcurl -X DELETE http://localhost:8787/api/auth/mfa/webauthn \ -H "Cookie: truss_session=your-session-token"Recovery Codes
Backup codes for account recovery when MFA devices are unavailable. Generate a set of one-time codes, confirm them, or revoke them.
Dashboard: Authentication > Settings (MFA section)
API Endpoints:
| Method | Path | Description |
|---|---|---|
POST | /api/auth/mfa/recovery-codes/generate | Generate a new set of recovery codes |
POST | /api/auth/mfa/recovery-codes/confirm | Confirm codes have been saved (activates them) |
DELETE | /api/auth/mfa/recovery-codes | Revoke all recovery codes |
# Generate recovery codescurl -X POST http://localhost:8787/api/auth/mfa/recovery-codes/generate \ -H "Cookie: truss_session=your-session-token"# Returns: { "codes": ["abc123", "def456", ...] }
# Confirm codes savedcurl -X POST http://localhost:8787/api/auth/mfa/recovery-codes/confirm \ -H "Cookie: truss_session=your-session-token"
# Revoke all codescurl -X DELETE http://localhost:8787/api/auth/mfa/recovery-codes \ -H "Cookie: truss_session=your-session-token"Passkeys
Passwordless FIDO2/WebAuthn assertion flow. Users can sign in with biometrics or a security key without entering a password.
Dashboard: Authentication > Login (passkey option)
API Endpoints:
| Method | Path | Description |
|---|---|---|
GET | /api/auth/login/passkey | Initialize a passkey login flow — returns assertion options |
POST | /api/auth/login/passkey | Complete passkey login with assertion response |
// Initialize passkey loginconst options = await fetch(`${TRUSS_URL}/api/auth/login/passkey`).then(r => r.json());
// Browser handles the key interactionconst assertion = await navigator.credentials.get({ publicKey: options.publicKey,});
// Complete loginconst session = await fetch(`${TRUSS_URL}/api/auth/login/passkey`, { method: "POST", headers: { "Content-Type": "application/json" }, body: JSON.stringify({ webauthn_login: JSON.stringify(assertion) }),}).then(r => r.json());# Initialize passkey login flowcurl http://localhost:8787/api/auth/login/passkey
# Complete passkey login (assertion response from browser)curl -X POST http://localhost:8787/api/auth/login/passkey \ -H "Content-Type: application/json" \ -d '{"webauthn_login": "<assertion-json>"}'Email OTP
Passwordless login via a one-time code sent to the user’s email address. The user enters the code to complete authentication.
This is configured in Kratos as the code strategy. The flow uses the standard Kratos settings flow with method: "code".
Dashboard: Authentication > Login
Magic Link
Email-based passwordless login. The user receives a link that authenticates them when clicked.
Dashboard: Authentication > Login (magic link option)
API Endpoints:
| Method | Path | Description |
|---|---|---|
POST | /api/auth/login/magic-link | Send a magic link to the user’s email |
# Send magic linkcurl -X POST http://localhost:8787/api/auth/login/magic-link \ -H "Content-Type: application/json" \ -d '{"email": "user@example.com"}'The Kratos link strategy handles token generation, email delivery, and session creation when the link is clicked.
Social / OIDC Login
Connect 18+ social identity providers for one-click sign-in. Truss displays brand icons for each configured provider.
Dashboard: Authentication > Overview (social login buttons)
Supported providers: Google, GitHub, Apple, Microsoft, Discord, GitLab, Facebook, Twitter/X, LinkedIn, Slack, Spotify, Twitch, Bitbucket, Dropbox, Yandex, VK, Dingtalk, and any custom OIDC provider.
API Endpoints:
| Method | Path | Description |
|---|---|---|
GET | /api/auth/providers | List configured OIDC providers with metadata |
Configuration:
# Enable providers (comma-separated)KRATOS_OIDC_PROVIDERS=google,github,apple,microsoft
# Each provider needs its own credentials in the Kratos config:# - client_id# - client_secret# - issuer_url (for generic OIDC)# - scope# - mapper_url (Jsonnet identity mapping)# List configured providerscurl http://localhost:8787/api/auth/providers \ -H "Cookie: truss_session=your-session-token"# Returns: [{ "id": "google", "label": "Google", "provider": "google" }, ...]Identity Management
User CRUD
Full create, read, update, and delete operations for user identities.
Dashboard: Authentication > Users tab
API Endpoints:
| Method | Path | Description |
|---|---|---|
GET | /api/auth/identities | List users (supports search and pagination) |
GET | /api/auth/identities/:id | Get a single user’s full identity |
POST | /api/auth/identities | Create a new user |
DELETE | /api/auth/identities/:id | Delete a user |
// List usersconst users = await fetch(`${TRUSS_URL}/api/auth/identities`, { credentials: "include",}).then(r => r.json());
// Get a single userconst user = await fetch(`${TRUSS_URL}/api/auth/identities/${userId}`, { credentials: "include",}).then(r => r.json());
// Create a userconst newUser = await fetch(`${TRUSS_URL}/api/auth/identities`, { method: "POST", credentials: "include", headers: { "Content-Type": "application/json" }, body: JSON.stringify({ email: "user@example.com", password: "securepassword123", }),}).then(r => r.json());
// Delete a userawait fetch(`${TRUSS_URL}/api/auth/identities/${userId}`, { method: "DELETE", credentials: "include",});import requests
TRUSS_URL = "http://localhost:8787"cookies = {"truss_session": "your-session-token"}
# List usersusers = requests.get(f"{TRUSS_URL}/api/auth/identities", cookies=cookies).json()
# Get a single useruser = requests.get(f"{TRUSS_URL}/api/auth/identities/{user_id}", cookies=cookies).json()
# Create a usernew_user = requests.post(f"{TRUSS_URL}/api/auth/identities", cookies=cookies, json={ "email": "user@example.com", "password": "securepassword123",}).json()
# Delete a userrequests.delete(f"{TRUSS_URL}/api/auth/identities/{user_id}", cookies=cookies)# List userscurl http://localhost:8787/api/auth/identities \ -H "Cookie: truss_session=your-session-token"
# Get a single usercurl http://localhost:8787/api/auth/identities/{id} \ -H "Cookie: truss_session=your-session-token"
# Create a usercurl -X POST http://localhost:8787/api/auth/identities \ -H "Content-Type: application/json" \ -H "Cookie: truss_session=your-session-token" \ -d '{"email": "user@example.com", "password": "securepassword123"}'
# Delete a usercurl -X DELETE http://localhost:8787/api/auth/identities/{id} \ -H "Cookie: truss_session=your-session-token"Server-Side Search
Search users by email, name, or credentials identifier. The search is performed server-side via Kratos admin API.
Dashboard: Authentication > Users tab (search bar)
# Search users by emailcurl "http://localhost:8787/api/auth/identities?search=alice@example" \ -H "Cookie: truss_session=your-session-token"The search query parameter filters identities by matching against email and name traits.
Cursor-Based Pagination
The identity list uses Kratos Link header-based cursor pagination for efficient infinite scroll through large user sets.
# First page (default 100 per page)curl "http://localhost:8787/api/auth/identities?per_page=50" \ -H "Cookie: truss_session=your-session-token"
# Subsequent pages use the cursor from the previous responsecurl "http://localhost:8787/api/auth/identities?per_page=50&page_token=<cursor>" \ -H "Cookie: truss_session=your-session-token"The response includes pagination metadata parsed from Kratos Link headers.
Batch Operations
Activate, deactivate, or delete up to 100 users at once. Select multiple users in the dashboard and apply a bulk action.
Dashboard: Authentication > Users tab (select checkbox > batch action dropdown)
API Endpoint:
| Method | Path | Description |
|---|---|---|
POST | /api/auth/identities/batch-action | Apply an action to multiple identities |
# Batch deactivate userscurl -X POST http://localhost:8787/api/auth/identities/batch-action \ -H "Content-Type: application/json" \ -H "Cookie: truss_session=your-session-token" \ -d '{ "action": "deactivate", "ids": ["id-1", "id-2", "id-3"] }'
# Batch delete userscurl -X POST http://localhost:8787/api/auth/identities/batch-action \ -H "Content-Type: application/json" \ -H "Cookie: truss_session=your-session-token" \ -d '{ "action": "delete", "ids": ["id-1", "id-2"] }'Supported actions: activate, deactivate, delete.
User State Management
Toggle users between active and inactive states. Inactive users cannot log in. The dashboard shows visual status chips (green for active, red for inactive/banned).
Dashboard: Authentication > Users tab (status column)
API Endpoint:
| Method | Path | Description |
|---|---|---|
PATCH | /api/auth/identities/:id/state | Set user state to active or inactive |
# Deactivate a usercurl -X PATCH http://localhost:8787/api/auth/identities/{id}/state \ -H "Content-Type: application/json" \ -H "Cookie: truss_session=your-session-token" \ -d '{"state": "inactive"}'
# Reactivate a usercurl -X PATCH http://localhost:8787/api/auth/identities/{id}/state \ -H "Content-Type: application/json" \ -H "Cookie: truss_session=your-session-token" \ -d '{"state": "active"}'Custom Metadata
Attach arbitrary JSON metadata to any user identity. Kratos supports two metadata buckets:
- Public metadata — visible to the user and client-side code
- Admin metadata — visible only to admin API callers
Dashboard: Authentication > Users > select user > Metadata tab (JSON editor)
API Endpoint:
| Method | Path | Description |
|---|---|---|
PUT | /api/auth/identities/:id/metadata | Update public and/or admin metadata |
curl -X PUT http://localhost:8787/api/auth/identities/{id}/metadata \ -H "Content-Type: application/json" \ -H "Cookie: truss_session=your-session-token" \ -d '{ "metadata_public": {"display_name": "Alice", "avatar_url": "https://..."}, "metadata_admin": {"plan": "pro", "notes": "VIP customer"} }'Multiple Identity Schemas
View and manage Kratos identity schemas. Each schema defines the traits (email, name, phone, etc.) that users of that type have.
Dashboard: Authentication > Schemas tab
API Endpoints:
| Method | Path | Description |
|---|---|---|
GET | /api/auth/schemas | List all identity schemas |
GET | /api/auth/schemas/:id | Get a specific schema with traits table and raw JSON |
# List schemascurl http://localhost:8787/api/auth/schemas \ -H "Cookie: truss_session=your-session-token"
# Get a specific schemacurl http://localhost:8787/api/auth/schemas/default \ -H "Cookie: truss_session=your-session-token"User Import (CSV/JSON)
Bulk import users from CSV or JSON files. Supports pre-hashed passwords so you can migrate from other auth providers without forcing password resets.
Dashboard: Authentication > Users tab > Import button
API Endpoint:
| Method | Path | Description |
|---|---|---|
POST | /api/auth/users/import | Import up to 500 users per batch |
curl -X POST http://localhost:8787/api/auth/users/import \ -H "Content-Type: application/json" \ -H "Cookie: truss_session=your-session-token" \ -d '{ "users": [ {"email": "alice@example.com", "password": "pass1234"}, {"email": "bob@example.com", "password": "pass5678"}, {"email": "carol@example.com", "password": "pass9012"} ] }'curl -X POST http://localhost:8787/api/auth/users/import \ -H "Content-Type: application/json" \ -H "Cookie: truss_session=your-session-token" \ -d '{ "users": [ { "email": "alice@example.com", "hashed_password": "$2a$12$abc...", "hash_format": "bcrypt" } ] }'User Export
Download all users as CSV or JSON for backup, migration, or analysis.
Dashboard: Authentication > Users tab > Export button
API Endpoint:
| Method | Path | Description |
|---|---|---|
GET | /api/auth/users/export | Export users (format=csv or format=json) |
# Export as JSONcurl "http://localhost:8787/api/auth/users/export?format=json" \ -H "Cookie: truss_session=your-session-token" \ -o users.json
# Export as CSVcurl "http://localhost:8787/api/auth/users/export?format=csv" \ -H "Cookie: truss_session=your-session-token" \ -o users.csvAdmin Impersonation
Create a session as another user for debugging purposes. This lets an admin see exactly what a user sees without knowing their password.
Dashboard: Authentication > Users > select user > Impersonate button
API Endpoint:
| Method | Path | Description |
|---|---|---|
POST | /api/auth/identities/:id/impersonate | Create a session token for the target user |
curl -X POST http://localhost:8787/api/auth/identities/{id}/impersonate \ -H "Cookie: truss_session=your-session-token"# Returns: { "session_token": "ory_st_..." }The returned session token can be used in the truss_session cookie to act as the impersonated user.
User Bans / Blocklist
Ban users with a state change plus metadata flag. Banned users show a red chip indicator in the dashboard and cannot log in.
Dashboard: Authentication > Users > select user > Ban / Unban buttons
API Endpoints:
| Method | Path | Description |
|---|---|---|
POST | /api/auth/identities/:id/ban | Ban a user (sets state to inactive + ban metadata) |
POST | /api/auth/identities/:id/unban | Unban a user (restores active state + clears ban flag) |
# Ban a usercurl -X POST http://localhost:8787/api/auth/identities/{id}/ban \ -H "Cookie: truss_session=your-session-token"
# Unban a usercurl -X POST http://localhost:8787/api/auth/identities/{id}/unban \ -H "Cookie: truss_session=your-session-token"Invite-Only Registration
Restrict sign-ups to users who have received an invitation. When enabled, the registration endpoint rejects requests without a valid invite token.
Configuration: Set TRUSS_INVITE_ONLY=true in your environment.
Dashboard: Authentication > Settings (invite-only toggle)
API Endpoints:
| Method | Path | Description |
|---|---|---|
POST | /api/auth/invite | Send an invitation email (admin only) |
GET | /api/auth/invitations | List pending invitations (admin only) |
# Send an invitationcurl -X POST http://localhost:8787/api/auth/invite \ -H "Content-Type: application/json" \ -H "Cookie: truss_session=your-session-token" \ -d '{"email": "newuser@example.com"}'
# List pending invitationscurl http://localhost:8787/api/auth/invitations \ -H "Cookie: truss_session=your-session-token"Session Management
Session Listing
View all active sessions for a user, including device info, IP address, and browser details.
Dashboard: Authentication > Users > select user > Sessions tab
API Endpoint:
| Method | Path | Description |
|---|---|---|
GET | /api/auth/sessions | List active sessions (optionally filter by identity) |
# List all active sessionscurl http://localhost:8787/api/auth/sessions \ -H "Cookie: truss_session=your-session-token"
# List sessions for a specific usercurl "http://localhost:8787/api/auth/sessions?identity_id={id}" \ -H "Cookie: truss_session=your-session-token"Session Revocation
Revoke a single session or all sessions for a user.
Dashboard: Authentication > Users > select user > Sessions tab > Revoke button
API Endpoints:
| Method | Path | Description |
|---|---|---|
DELETE | /api/auth/sessions/:id | Revoke a single session |
DELETE | /api/auth/identities/:id/sessions | Revoke all sessions for a user (force logout) |
# Revoke a single sessioncurl -X DELETE http://localhost:8787/api/auth/sessions/{sessionId} \ -H "Cookie: truss_session=your-session-token"
# Force-logout a user (revoke all their sessions)curl -X DELETE http://localhost:8787/api/auth/identities/{userId}/sessions \ -H "Cookie: truss_session=your-session-token"Session Lifespan Configuration
Configure how long sessions last before expiring. The current session TTL is displayed in the security dashboard.
Dashboard: Authentication > Security tab (session lifespan display)
Session lifespan is configured in the Kratos configuration file:
session: lifespan: 720h # 30 days cookie: same_site: LaxDevice / Browser Tracking
Each session records the IP address and parsed user agent (browser name, OS). This data is displayed in the session list.
Dashboard: Authentication > Users > select user > Sessions tab
Session objects include:
devices[].ip_address— Client IPdevices[].user_agent— Raw user agent string- Parsed browser and OS names for display
Login History
Full login history with IP address, user agent, timestamp, and success/failure status. Filterable and paginated.
Dashboard: Authentication > Audit tab
API Endpoint:
| Method | Path | Description |
|---|---|---|
GET | /api/auth/login-history | Get login history (admin only) |
curl "http://localhost:8787/api/auth/login-history?limit=50&offset=0" \ -H "Cookie: truss_session=your-session-token"Returns entries with: timestamp, identity ID, email, IP address, user agent, method (password/oidc/passkey), and success status.
Force Re-Authentication
Revoke all sessions for a user to force them to log in again. Useful when credentials may be compromised.
# Force re-auth for a specific usercurl -X DELETE http://localhost:8787/api/auth/identities/{id}/sessions \ -H "Cookie: truss_session=your-session-token"Session Extend
Admins can extend an active session’s lifespan via the API.
API Endpoint:
| Method | Path | Description |
|---|---|---|
PATCH | /api/auth/sessions/:id/extend | Extend an active session |
curl -X PATCH http://localhost:8787/api/auth/sessions/{sessionId}/extend \ -H "Cookie: truss_session=your-session-token"Security
Breached Password Detection (HIBP)
Truss integrates with the Have I Been Pwned (HIBP) API to check passwords against known data breaches. When enabled, users cannot set passwords that appear in breach databases.
Dashboard: Authentication > Security tab
This is configured in Kratos:
selfservice: methods: password: config: haveibeenpwned_enabled: truePassword Policy
Configure minimum password length, similarity checks, and other rules.
Dashboard: Authentication > Security tab (password policy display)
API Endpoint:
| Method | Path | Description |
|---|---|---|
GET | /api/auth/security-config | Get current security configuration (admin only) |
curl http://localhost:8787/api/auth/security-config \ -H "Cookie: truss_session=your-session-token"Returns the active Kratos security configuration including password policy, MFA settings, and session lifespan.
Kratos password policy options:
selfservice: methods: password: config: min_password_length: 8 identifier_similarity_check_enabled: true haveibeenpwned_enabled: true max_breaches: 0 # Reject any breached passwordMFA Enforcement
Require the highest available authentication level. When enabled, users with MFA configured must always provide their second factor.
Configured in the Kratos identity schema via aal (Authenticator Assurance Level):
aal1— Password onlyaal2— Password + second factor required
Account Enumeration Protection
Kratos natively protects against user enumeration attacks. Login and registration flows return identical responses whether an account exists or not, preventing attackers from discovering valid email addresses.
This is enabled by default in Kratos and requires no additional configuration.
Brute Force Protection
Flow TTL limits throttle automated login attempts. Each Kratos flow has a configurable time-to-live, and expired flows must be re-initialized.
selfservice: flows: login: lifespan: 10m # Flow expires after 10 minutes registration: lifespan: 10mAccount Recovery & Verification
Email Verification
Trigger a verification email for a user’s email address from the admin dashboard.
Dashboard: Authentication > Users > select user > Send Verification button
API Endpoint:
| Method | Path | Description |
|---|---|---|
POST | /api/auth/identities/:id/send-verification | Send a verification email to the user |
curl -X POST http://localhost:8787/api/auth/identities/{id}/send-verification \ -H "Cookie: truss_session=your-session-token"Password Recovery
Trigger a recovery email or generate a one-time recovery link for a user.
Dashboard: Authentication > Users > select user > Send Recovery / Reset Password buttons
API Endpoints:
| Method | Path | Description |
|---|---|---|
POST | /api/auth/identities/:id/send-recovery | Send a recovery email to the user |
POST | /api/auth/identities/:id/reset-password | Directly reset a user’s password (admin) |
# Send recovery emailcurl -X POST http://localhost:8787/api/auth/identities/{id}/send-recovery \ -H "Cookie: truss_session=your-session-token"
# Directly reset a password (admin)curl -X POST http://localhost:8787/api/auth/identities/{id}/reset-password \ -H "Content-Type: application/json" \ -H "Cookie: truss_session=your-session-token" \ -d '{"password": "newpassword123"}'Recovery Link / Code Generation
Generate a direct recovery link with a 1-hour expiry. Useful for support scenarios where you need to send a user a link manually.
API Endpoint:
| Method | Path | Description |
|---|---|---|
POST | /api/auth/identities/:id/create-recovery-link | Generate a one-time recovery link |
curl -X POST http://localhost:8787/api/auth/identities/{id}/create-recovery-link \ -H "Cookie: truss_session=your-session-token"# Returns: { "recovery_link": "https://...", "expires_at": "2026-03-15T..." }The link expires after 1 hour and can only be used once.
Hooks & Events
Auth Webhooks
Configure webhooks that fire on authentication events. Each webhook includes HMAC-SHA256 signing for verification and supports test-firing.
Dashboard: Authentication > Webhooks tab
API Endpoints:
| Method | Path | Description |
|---|---|---|
GET | /api/auth/webhooks | List configured auth webhooks |
PUT | /api/auth/webhooks | Create or update auth webhooks |
POST | /api/auth/webhooks/test | Test-fire a webhook |
Supported events: login, register, recovery, verification, logout
# List auth webhookscurl http://localhost:8787/api/auth/webhooks \ -H "Cookie: truss_session=your-session-token"
# Configure webhookscurl -X PUT http://localhost:8787/api/auth/webhooks \ -H "Content-Type: application/json" \ -H "Cookie: truss_session=your-session-token" \ -d '{ "webhooks": [{ "url": "https://your-server.com/webhook", "events": ["login", "register"], "secret": "your-hmac-secret" }] }'
# Test-fire a webhookcurl -X POST http://localhost:8787/api/auth/webhooks/test \ -H "Content-Type: application/json" \ -H "Cookie: truss_session=your-session-token" \ -d '{"url": "https://your-server.com/webhook", "secret": "your-hmac-secret"}'Verifying webhook signatures (JavaScript):
import crypto from "node:crypto";
function verifyWebhook(payload, signature, secret) { const expected = crypto .createHmac("sha256", secret) .update(payload) .digest("hex"); return crypto.timingSafeEqual( Buffer.from(signature), Buffer.from(expected) );}Custom Email Templates
Customize the email templates used for verification, recovery, and welcome emails. Templates support variable substitution.
Dashboard: Authentication > Email Templates tab
API Endpoints:
| Method | Path | Description |
|---|---|---|
GET | /api/auth/email-templates | List current email templates |
PUT | /api/auth/email-templates | Update email templates |
# Get current templatescurl http://localhost:8787/api/auth/email-templates \ -H "Cookie: truss_session=your-session-token"
# Update templatescurl -X PUT http://localhost:8787/api/auth/email-templates \ -H "Content-Type: application/json" \ -H "Cookie: truss_session=your-session-token" \ -d '{ "verification": { "subject": "Verify your email for {{.ApplicationName}}", "body_html": "<h1>Welcome!</h1><p>Click <a href=\"{{.VerificationURL}}\">here</a> to verify.</p>" }, "recovery": { "subject": "Reset your password", "body_html": "<p>Click <a href=\"{{.RecoveryURL}}\">here</a> to reset your password.</p>" } }'Available template variables: {{.VerificationURL}}, {{.RecoveryURL}}, {{.ApplicationName}}, {{.Identity.traits.email}}.
Session Hook
Auto-login after registration. When configured, users are automatically signed in after completing the registration flow (no separate login step).
This is a Kratos after-registration hook:
selfservice: flows: registration: after: password: hooks: - hook: sessionDeveloper Experience
Prebuilt UI Components
Copy-paste authentication components for common frameworks. Available in the dashboard under Authentication > SDK tab.
import { useState } from "react";
function LoginForm({ onSuccess }) { const [email, setEmail] = useState(""); const [password, setPassword] = useState(""); const [error, setError] = useState(null);
const handleSubmit = async (e) => { e.preventDefault(); const res = await fetch("/api/auth/login", { method: "GET" }); const { flow_id } = await res.json(); const login = await fetch("/api/auth/login", { method: "POST", headers: { "Content-Type": "application/json" }, body: JSON.stringify({ flow_id, email, password }), }); if (login.ok) onSuccess(await login.json()); else setError("Invalid credentials"); };
return ( <form onSubmit={handleSubmit}> <input type="email" value={email} onChange={e => setEmail(e.target.value)} placeholder="Email" /> <input type="password" value={password} onChange={e => setPassword(e.target.value)} placeholder="Password" /> {error && <p style={{ color: "red" }}>{error}</p>} <button type="submit">Sign in</button> </form> );}from flask import Flask, request, redirect, sessionimport requests
app = Flask(__name__)TRUSS_URL = "http://localhost:8787"
@app.route("/login", methods=["GET", "POST"])def login(): if request.method == "POST": email = request.form["email"] password = request.form["password"]
# Initialize flow flow = requests.get(f"{TRUSS_URL}/api/auth/login").json()
# Submit credentials res = requests.post(f"{TRUSS_URL}/api/auth/login", json={ "flow_id": flow["flow_id"], "email": email, "password": password, }) if res.ok: session["token"] = res.json()["session_token"] return redirect("/dashboard") return "Invalid credentials", 401 return '<form method="POST"><input name="email"><input name="password" type="password"><button>Login</button></form>'package main
import ( "encoding/json" "fmt" "net/http" "strings")
func loginHandler(w http.ResponseWriter, r *http.Request) { if r.Method == "POST" { r.ParseForm() email := r.FormValue("email") password := r.FormValue("password")
// Initialize flow resp, _ := http.Get("http://localhost:8787/api/auth/login") var flow map[string]string json.NewDecoder(resp.Body).Decode(&flow)
// Submit credentials body := fmt.Sprintf(`{"flow_id":"%s","email":"%s","password":"%s"}`, flow["flow_id"], email, password) loginResp, _ := http.Post("http://localhost:8787/api/auth/login", "application/json", strings.NewReader(body))
if loginResp.StatusCode == 200 { var result map[string]string json.NewDecoder(loginResp.Body).Decode(&result) http.SetCookie(w, &http.Cookie{Name: "session", Value: result["session_token"]}) http.Redirect(w, r, "/dashboard", http.StatusFound) return } http.Error(w, "Invalid credentials", 401) }}SDK Snippets
Complete SDK examples for all 6 core auth flows (sign up, sign in, get session, update settings, recovery, logout) in 4 languages.
Dashboard: Authentication > SDK tab
import { Configuration, FrontendApi } from "@ory/client";
const kratos = new FrontendApi(new Configuration({ basePath: "http://localhost:4433", baseOptions: { withCredentials: true },}));
// Sign upconst { data: flow } = await kratos.createBrowserRegistrationFlow();await kratos.updateRegistrationFlow({ flow: flow.id, updateRegistrationFlowBody: { method: "password", password: "securePass123", traits: { email: "user@example.com" }, },});
// Sign inconst { data: loginFlow } = await kratos.createBrowserLoginFlow();await kratos.updateLoginFlow({ flow: loginFlow.id, updateLoginFlowBody: { method: "password", identifier: "user@example.com", password: "securePass123", },});
// Get current sessionconst { data: session } = await kratos.toSession();console.log(session.identity.traits.email);
// Logoutconst { data: logoutFlow } = await kratos.createBrowserLogoutFlow();await kratos.updateLogoutFlow({ token: logoutFlow.logout_token });import ory_client
config = ory_client.Configuration(host="http://localhost:4433")api = ory_client.FrontendApi(ory_client.ApiClient(config))
# Sign upflow = api.create_browser_registration_flow()api.update_registration_flow( flow=flow.id, update_registration_flow_body={ "method": "password", "password": "securePass123", "traits": {"email": "user@example.com"}, },)
# Sign inlogin_flow = api.create_browser_login_flow()api.update_login_flow( flow=login_flow.id, update_login_flow_body={ "method": "password", "identifier": "user@example.com", "password": "securePass123", },)
# Get current sessionsession = api.to_session()print(session.identity.traits["email"])import ory "github.com/ory/client-go"
config := ory.NewConfiguration()config.Servers = ory.ServerConfigurations{{URL: "http://localhost:4433"}}client := ory.NewAPIClient(config)
// Sign upflow, _, _ := client.FrontendAPI.CreateBrowserRegistrationFlow(ctx).Execute()_, _, _ = client.FrontendAPI.UpdateRegistrationFlow(ctx). Flow(flow.Id). UpdateRegistrationFlowBody(ory.UpdateRegistrationFlowBody{ UpdateRegistrationFlowWithPasswordMethod: &ory.UpdateRegistrationFlowWithPasswordMethod{ Method: "password", Password: "securePass123", Traits: map[string]interface{}{"email": "user@example.com"}, }, }).Execute()
// Sign inloginFlow, _, _ := client.FrontendAPI.CreateBrowserLoginFlow(ctx).Execute()_, _, _ = client.FrontendAPI.UpdateLoginFlow(ctx). Flow(loginFlow.Id). UpdateLoginFlowBody(ory.UpdateLoginFlowBody{ UpdateLoginFlowWithPasswordMethod: &ory.UpdateLoginFlowWithPasswordMethod{ Method: "password", Identifier: "user@example.com", Password: "securePass123", }, }).Execute()
// Get current sessionsession, _, _ := client.FrontendAPI.ToSession(ctx).Execute()fmt.Println(session.Identity.Traits.(map[string]interface{})["email"])Auth Overview Dashboard
The Authentication overview shows at-a-glance stats and recent activity.
Dashboard: Authentication > Overview tab
Stats cards:
- Total users (active + inactive)
- Logins in last 24 hours
- Failed logins in last 24 hours
API Endpoint:
| Method | Path | Description |
|---|---|---|
GET | /api/auth/stats | Get authentication statistics (admin only) |
curl http://localhost:8787/api/auth/stats \ -H "Cookie: truss_session=your-session-token"# Returns: { "total_users": 1234, "logins_24h": 89, "failed_24h": 3 }Audit Log
All authentication actions are logged to the audit trail. Filter by action type, search term, or date range.
Dashboard: Authentication > Audit tab
API Endpoint:
| Method | Path | Description |
|---|---|---|
GET | /v1/audit-logs | Query audit logs (requires service_role API key) |
# Query audit logs via client APIcurl "http://localhost:8787/v1/audit-logs?action=auth.login&limit=50" \ -H "apikey: truss_sk_your_key"Logged actions include: auth.login, auth.register, auth.logout, auth.identity.create, auth.identity.delete, auth.identity.ban, auth.identity.unban, auth.mfa.totp.setup, auth.mfa.webauthn.setup, and more.
Client API
The client API provides identity management for external tools and scripts, authenticated via API key rather than session cookie.
Base path: /v1/auth/
| Method | Path | Description |
|---|---|---|
GET | /v1/auth/identities | List identities (requires service_role key) |
GET | /v1/auth/identities/:id | Get identity detail (requires service_role key) |
const API_KEY = "truss_sk_your_service_role_key";
// List identitiesconst users = await fetch("http://localhost:8787/v1/auth/identities", { headers: { apikey: API_KEY },}).then(r => r.json());
// Get identity detailconst user = await fetch(`http://localhost:8787/v1/auth/identities/${userId}`, { headers: { apikey: API_KEY },}).then(r => r.json());# List identitiescurl http://localhost:8787/v1/auth/identities \ -H "apikey: truss_sk_your_key"
# Get identity detailcurl http://localhost:8787/v1/auth/identities/{id} \ -H "apikey: truss_sk_your_key"Settings Flow
Users can update their own profile, password, and MFA settings through the settings flow.
Dashboard: User menu > Settings
API Endpoints:
| Method | Path | Description |
|---|---|---|
GET | /api/auth/settings | Initialize a settings flow |
POST | /api/auth/settings | Update settings (profile, password, MFA) |
# Initialize settings flowcurl http://localhost:8787/api/auth/settings \ -H "Cookie: truss_session=your-session-token"
# Update passwordcurl -X POST http://localhost:8787/api/auth/settings \ -H "Content-Type: application/json" \ -H "Cookie: truss_session=your-session-token" \ -d '{ "method": "password", "password": "newSecurePassword123" }'
# Update profile traitscurl -X POST http://localhost:8787/api/auth/settings \ -H "Content-Type: application/json" \ -H "Cookie: truss_session=your-session-token" \ -d '{ "method": "profile", "traits": {"email": "newemail@example.com", "name": "Alice"} }'Registration
API Endpoints:
| Method | Path | Description |
|---|---|---|
GET | /api/auth/register | Initialize a registration flow |
POST | /api/auth/register | Complete registration |
# Initialize registrationcurl http://localhost:8787/api/auth/register
# Register with email + passwordcurl -X POST http://localhost:8787/api/auth/register \ -H "Content-Type: application/json" \ -d '{ "email": "newuser@example.com", "password": "securePass123" }'When TRUSS_INVITE_ONLY=true, registration requires a valid invite token.