Complete reference for all HTTP endpoints exposed by the Auth authentication server.
All endpoints are served over HTTPS only. The base URL is https://{host}:{port}.
- Public Endpoints
- Authentication — Login and Session Claims
- Session Management
- Realm Administration
- User Administration
- Credential Management
- TOTP Management
- Common Response Codes
- Authentication for Admin Endpoints
- Data Types
No authentication required.
Returns the server version string.
Response
HTTP/1.1 200 OK
Content-Type: text/plain
"0.1.2"
Returns the JSON Web Key Set containing the server's public key(s) for JWT signature verification.
Note: Only available in test builds. Production deployments expose JWKS through the Identity Provider's own JWKS endpoint.
Response
{
"keys": [
{
"kty": "EC",
"crv": "P-256",
"x": "...",
"y": "...",
"use": "sig"
}
]
}Authenticate a client and issue a session cookie. The authentication method is determined by the Authorization header or the request body.
Authentication methods:
| Method | How to supply credentials |
|---|---|
| Username/Password | Authorization: Basic <base64(username:password)> |
| JWT Bearer | Authorization: Bearer <jwt_token> |
| Client Certificate | Client certificate in TLS handshake |
Request body (optional — for public-key FIDO2 challenge or TOTP code)
{
"public_key_pem": null,
"totp_code": "482913"
}| Field | Type | Description |
|---|---|---|
public_key_pem |
String | null |
Client public key (FIDO2 / digital credentials flows) |
totp_code |
String | null |
TOTP verification code for 2FA step |
Response — 200 OK
{
"next_step": "Authenticated",
"session_id": "550e8400-e29b-41d4-a716-446655440000"
}Set-Cookie header: _ea_=<cookie_string>; HttpOnly; Secure; SameSite=Strict
| Field | Type | Description |
|---|---|---|
next_step |
"Authenticated" | "TotpRequired" | "ChangePassword" |
What the client should do next |
session_id |
String | null |
UUID of the new session (only present when Authenticated) |
Response — 401 Unauthorized — credentials invalid or missing.
Response — 200 OK with "next_step": "TotpRequired" — primary credentials valid but TOTP code is required. Re-submit the request with totp_code.
Returns the JWT claims for the currently authenticated session.
Authentication: Session cookie (_ea_ cookie).
Response — 200 OK
{
"iss": "auth-auth",
"sub": "alice",
"aud": ["my-service"],
"exp": 1745000000,
"iat": 1744996400,
"as_as": "up",
"as_rid": "my-service"
}See Data Types — ClientClaims for the full field reference.
Response — 401 Unauthorized — no valid session cookie.
Retrieve session data by session ID. Returns null (not an error) when the session does not exist or has expired.
Response — 200 OK (session found)
{
"session_id": "550e8400-e29b-41d4-a716-446655440000",
"realm_id": "my-service",
"username": "alice",
"auth_scheme": "up",
"cookie_string": "eyJ…",
"max_age_seconds": 3600,
"max_stale_age_seconds": 1800,
"created_at": 1744996400
}Response — 200 OK (session not found)
nullRetrieve session data and optionally apply a bulk logout action in the same request.
Request body
{
"authenticated_clients": [
{ "username": "alice", "auth_scheme": "UsernamePassword" }
],
"sessions_action": "LogoutOtherSessions"
}| Field | Type | Description |
|---|---|---|
authenticated_clients |
AuthenticatedClientScheme[] |
Clients whose sessions may be affected |
sessions_action |
"LogoutOtherSessions" | "LogoutAllSessions" | null |
Action to perform alongside the lookup |
sessions_action values:
| Value | Effect |
|---|---|
"LogoutOtherSessions" |
Delete all sessions for the given clients except the queried one |
"LogoutAllSessions" |
Delete all sessions for the given clients (including the queried one); session data is returned before deletion |
Response — 200 OK — same shape as GET /sessions/session/{id}.
Return all session IDs for a set of authenticated clients in a realm.
Request body
[
{ "username": "alice", "auth_scheme": "UsernamePassword" },
{ "username": "alice", "auth_scheme": "Jwt" }
]Response — 200 OK
{
"session_ids": [
"550e8400-e29b-41d4-a716-446655440000",
"660f9511-f3ac-52e5-c827-557766551111"
]
}Delete sessions by ID.
Request body
{
"session_ids": [
"550e8400-e29b-41d4-a716-446655440000"
]
}Response — 200 OK — empty body.
Delete all expired sessions from the session store.
Response — 200 OK — empty body.
Delete all sessions for a given realm (administrative bulk logout).
Response — 200 OK — empty body.
All endpoints under /admin require the caller to be authenticated as a super admin (a User whose realms list contains "_").
Create a new realm.
Request body
{
"id": "my-service",
"auth_params": {
"username_password_params": {
"allow_expired_passwords": false
}
},
"session_max_age_seconds": 3600,
"session_max_stale_age_seconds": 1800
}Response — 200 OK — empty body on success.
Response — 409 Conflict — realm ID already exists.
Retrieve a realm by ID.
Response — 200 OK
{
"id": "my-service",
"auth_params": { "username_password_params": { "allow_expired_passwords": false } },
"session_max_age_seconds": 3600,
"session_max_stale_age_seconds": 1800
}Response — 404 Not Found — realm does not exist.
Replace a realm's configuration. Returns the updated realm.
Request body — same shape as POST /admin/realm.
Response — 200 OK — updated Realm object.
Delete a realm and all associated data.
Response — 200 OK — empty body.
List all realms.
Response — 200 OK
[
{
"id": "_",
"auth_params": {},
"session_max_age_seconds": 3600,
"session_max_stale_age_seconds": 3600
},
{
"id": "my-service",
...
}
]List all username/password credentials across every realm (super admin only).
Response — 200 OK — array of UserPass objects. The password field is always returned as an empty byte array.
Create a new User record. Super admin only.
Request body
{
"id": "bob",
"realms": ["my-service"],
"userpass": "bob",
"jwt": null,
"fido2": null,
"digital_credentials": null,
"client_certificate": null,
"totp_enabled": false,
"totp_secret": null,
"totp_auth_url": null
}| Field | Type | Description |
|---|---|---|
id |
String |
Unique user identifier |
realms |
String[] |
Realms this user administers. Use ["_"] for super admin. |
userpass |
String | null |
Username key referencing the userpass credential table |
jwt |
String | null |
JWT subject identifier |
fido2 |
String | null |
FIDO2 identifier (future) |
digital_credentials |
Object | null |
Key-value map of digital credential identifiers (future) |
client_certificate |
String | null |
Client certificate identifier |
totp_enabled |
bool | null |
Whether TOTP is active for this user |
totp_secret |
String | null |
Base32-encoded TOTP secret (read-only via API) |
totp_auth_url |
String | null |
otpauth:// URL for QR code enrollment (read-only) |
Response — 200 OK — created User object.
Retrieve a user by ID.
Response — 200 OK — User object.
Response — 404 Not Found — user does not exist.
Replace a user record. Returns the updated user.
Request body — same shape as POST /users/user.
Response — 200 OK — updated User object.
Delete a user record.
Response — 200 OK — empty body.
List all users. Super admin only.
Response — 200 OK — array of User objects.
Add a realm to a user's realms list.
Response — 200 OK — updated User object.
Remove a realm from a user's realms list.
Response — 200 OK — updated User object.
All /realms/{realm} endpoints require a valid session from a user who administers the given realm (see authorization_and_administration.md).
Create a username/password credential in a realm.
Request body
{
"realm": "my-service",
"username": "alice",
"password": [115, 101, 99, 114, 101, 116],
"change_password": false
}| Field | Type | Description |
|---|---|---|
realm |
String |
Realm ID (must match path parameter) |
username |
String |
Credential username |
password |
u8[] |
UTF-8 bytes of the plaintext password. The server hashes with Argon2id. |
change_password |
bool |
When true, the next login returns "ChangePassword" next step |
Response — 200 OK — empty body.
List all credentials in a realm.
Response — 200 OK — array of UserPass objects. The password field is always empty.
Retrieve a single credential.
Response — 200 OK — UserPass object. The password field is always empty.
Response — 404 Not Found — credential does not exist.
Update a credential (typically to change the password or set change_password).
Request body — same shape as POST /realms/{realm}/userpass.
Response — 200 OK — updated UserPass object.
Delete a credential.
Response — 200 OK — empty body.
See two_factor_authentication.md for the full enrollment flow.
Generate a TOTP secret for a user. The secret is not stored at this point — it is only persisted after a successful verification call.
Query parameters: realm={realm_id}
Request body
{
"username": "alice",
"issuer": "My Application"
}Response — 200 OK
{
"secret_base32": "JBSWY3DPEHPK3PXP",
"otpauth_url": "otpauth://totp/My%20Application:alice?secret=JBSWY3DPEHPK3PXP&issuer=My%20Application&algorithm=SHA1&digits=6&period=30"
}Verify a TOTP code and enable TOTP for the user. Call this after generate to confirm the user has enrolled their authenticator app.
Query parameters: realm={realm_id}
Request body
{
"username": "alice",
"token": "482913",
"secret": "JBSWY3DPEHPK3PXP",
"issuer": "My Application"
}Response — 200 OK — empty body. TOTP is now active for the user.
Response — 400 Bad Request — TOTP token is invalid.
Disable TOTP for a user.
Query parameters: realm={realm_id}
Response — 200 OK — empty body.
| Code | Meaning |
|---|---|
200 OK |
Success |
400 Bad Request |
Malformed request body or invalid parameter |
401 Unauthorized |
Missing or invalid credentials |
403 Forbidden |
Authenticated but not authorised (e.g., realm admin trying to modify another realm) |
404 Not Found |
Resource does not exist |
409 Conflict |
Resource already exists (duplicate ID) |
500 Internal Server Error |
Unexpected server error |
Admin endpoints (/admin, /users, /realms) require a valid session cookie obtained by logging into the _ realm (super admin) or the target realm (realm admin).
# Log in as super admin
curl --cacert ca.cert.pem \
-X POST "https://localhost:8443/login?realm=_" \
-u "admin:password" \
-c cookies.txt
# Use the session cookie for admin calls
curl --cacert ca.cert.pem \
-b cookies.txt \
https://localhost:8443/admin/realmsSee authorization_and_administration.md for the full authorization matrix.
{
"id": "my-service",
"auth_params": {
"username_password_params": { "allow_expired_passwords": false },
"jwt_params": {
"idp_params": [
{
"jwt_issuer_uri": "https://accounts.google.com",
"jwks_uri": "https://www.googleapis.com/oauth2/v3/certs",
"jwt_audience": "my-client-id.apps.googleusercontent.com"
}
],
"smallest_refresh_interval_seconds": 300
},
"totp_params": { "algorithm": "SHA1", "step": 30 }
},
"session_max_age_seconds": 3600,
"session_max_stale_age_seconds": 1800
}{
"id": "alice",
"realms": ["my-service"],
"userpass": "alice",
"jwt": null,
"fido2": null,
"digital_credentials": null,
"client_certificate": null,
"totp_enabled": false,
"totp_secret": null,
"totp_auth_url": null
}{
"realm": "my-service",
"username": "alice",
"password": [],
"change_password": false
}The
passwordfield is always returned as an empty byte array from GET endpoints. Send the plaintext UTF-8 bytes only on create/update.
{
"session_id": "550e8400-e29b-41d4-a716-446655440000",
"realm_id": "my-service",
"username": "alice",
"auth_scheme": "up",
"cookie_string": "eyJ…",
"max_age_seconds": 3600,
"max_stale_age_seconds": 1800,
"created_at": 1744996400
}| Field | Description |
|---|---|
auth_scheme |
"up" username/password · "jwt" JWT · "cc" client cert · "f2" FIDO2 · "dc" digital credentials |
{ "username": "alice", "auth_scheme": "UsernamePassword" }auth_scheme values: "UsernamePassword", "Jwt", "ClientCertificate", "Fido2", "DigitalCredentials"
The JWT payload returned by GET /whoami:
| Claim | Type | Description |
|---|---|---|
iss |
String |
Issuer |
sub |
String |
Subject (authenticated username) |
aud |
String[] |
Audience list |
exp |
i64 |
Expiration (Unix seconds) |
nbf |
i64 |
Not-before (Unix seconds) |
iat |
i64 |
Issued-at (Unix seconds) |
jti |
String |
JWT ID |
as_as |
String |
Auth scheme used (up/jwt/cc/f2/dc) |
as_pk |
String |
Client public key PEM (when applicable) |
as_rid |
String |
Realm ID |