API Overview
The IdentSphere HTTP API is a small, opinionated REST surface. All endpoints live
under a single base URL — by convention https://auth.example.com — and
follow the same conventions for authentication, errors, and content types.
::: tip Stability Every endpoint documented here is part of the v0.1 stable contract. Breaking changes will only land in major version bumps (v1, v2, …). Additive changes (new optional request fields, new response fields) may ship in minor versions. :::
Base URL
The SDK doesn't enforce a particular host. In the docs we use:
| Role | Example URL |
|---|---|
| Auth backend | https://auth.example.com |
| Your app frontend | https://app.example.com |
| Object storage CDN | https://files.example.com |
Replace these with whatever your deployment uses. For local development
the defaults are http://localhost:4000 (auth) and http://localhost:3000
(app).
Route prefix
By default every endpoint is mounted under /v1. The prefix is configurable
via AppConfig::route_prefix — if you change it (for example to /auth/v1)
adjust every URL in this reference accordingly.
Endpoint catalog
Auth
| Method | Path | Auth | Notes |
|---|---|---|---|
| POST | /v1/auth/register | none | Create org + owner user |
| POST | /v1/auth/login | none | Email + password sign-in. May return mfa_required. |
| POST | /v1/auth/refresh | refresh cookie | Rotate refresh token, mint new access token |
| POST | /v1/auth/logout | optional | Revoke the current session |
| GET | /v1/auth/session | cookie/Bearer | Current user + capabilities |
MFA (TOTP)
| Method | Path | Auth |
|---|---|---|
| GET | /v1/auth/mfa/status | cookie/Bearer |
| POST | /v1/auth/mfa/setup | cookie/Bearer |
| POST | /v1/auth/mfa/enable | cookie/Bearer |
| POST | /v1/auth/mfa/disable | cookie/Bearer + password |
| POST | /v1/auth/mfa/recovery-codes | cookie/Bearer + password |
| POST | /v1/auth/mfa/verify | cookie/Bearer |
| POST | /v1/auth/mfa/challenge | mfa_token (from login) |
Passkeys (WebAuthn)
| Method | Path | Auth |
|---|---|---|
| POST | /v1/users/me/passkeys/register/begin | cookie/Bearer |
| POST | /v1/users/me/passkeys/register/complete | cookie/Bearer |
| GET | /v1/users/me/passkeys | cookie/Bearer |
| DELETE | /v1/users/me/passkeys/:id | cookie/Bearer |
| POST | /v1/auth/passkey/login/begin | none |
| POST | /v1/auth/passkey/login/complete | none |
OAuth
| Method | Path | Auth |
|---|---|---|
| GET | /v1/auth/oauth/:provider/start | none |
| GET | /v1/auth/oauth/:provider/callback | none |
Email OTP / verification / password reset
| Method | Path | Auth |
|---|---|---|
| POST | /v1/auth/email-otp/request | none |
| POST | /v1/auth/email-otp/verify | none |
| POST | /v1/auth/email/send-verification | cookie/Bearer |
| POST | /v1/auth/email/verify | none |
| POST | /v1/auth/password/forgot | none |
| POST | /v1/auth/password/reset | none |
Sessions
| Method | Path | Auth |
|---|---|---|
| GET | /v1/auth/sessions | cookie/Bearer |
| DELETE | /v1/auth/sessions/:id | cookie/Bearer |
| DELETE | /v1/auth/sessions | cookie/Bearer |
Trusted browsers
| Method | Path | Auth |
|---|---|---|
| POST | /v1/auth/trusted-browsers | cookie/Bearer |
| GET | /v1/auth/trusted-browsers | cookie/Bearer |
| DELETE | /v1/auth/trusted-browsers/:id | cookie/Bearer |
Users
| Method | Path | Auth |
|---|---|---|
| GET | /v1/users/me | cookie/Bearer |
| PATCH | /v1/users/me | cookie/Bearer |
| POST | /v1/users/me/password | cookie/Bearer |
| POST | /v1/users/me/avatar | cookie/Bearer |
| DELETE | /v1/users/me/avatar | cookie/Bearer |
Invitations + team
| Method | Path | Auth |
|---|---|---|
| POST | /v1/orgs/:org_id/invitations | cookie/Bearer + members.invite |
| GET | /v1/orgs/:org_id/invitations | cookie/Bearer + members.list |
| DELETE | /v1/orgs/:org_id/invitations/:id | cookie/Bearer + members.invite |
| POST | /v1/orgs/:org_id/invitations/:id/resend | cookie/Bearer + members.invite |
| GET | /v1/auth/invitations/preview | none (token in query) |
| POST | /v1/auth/invitations/accept | none / optional |
| GET | /v1/orgs/:org_id/members | cookie/Bearer + members.list |
| PATCH | /v1/orgs/:org_id/members/:user_id | cookie/Bearer + role grant authz |
| DELETE | /v1/orgs/:org_id/members/:user_id | cookie/Bearer + members.remove |
The LoginResponse discriminated union
POST /v1/auth/register, POST /v1/auth/login, POST /v1/auth/mfa/challenge,
POST /v1/auth/passkey/login/complete, POST /v1/auth/email-otp/verify,
and POST /v1/auth/invitations/accept (new-user branch) all share a single
response shape, discriminated by the status field:
// status = "success" — full session issued
{
"status": "success",
"user": { "user_id": "...", "organization_id": "...", "email": "alice@example.com", "auth_method": "password", "session_family_id": "...", "scopes": [], "allowed_ips": [], "allowed_referrers": [], "extensions": {} },
"capabilities": { "role": "owner", "permissions": ["..."] },
"access_token": "eyJ...",
"expires_in": 900
}
// status = "mfa_required" — caller must complete MFA challenge
{
"status": "mfa_required",
"mfa_token": "eyJ...",
"mfa_token_expires_in": 300
}
Always switch on status before reading the rest of the body — accessing
access_token on an mfa_required response is a TypeScript-side error.
Error envelope
Every non-2xx response follows the same shape:
{
"error": {
"code": "invalid_input",
"message": "email must be a valid email address",
"type": "validation_error"
}
}
code— a stable machine-readable string. Safe to switch on in code.message— a human-readable explanation. Localize at your discretion.type— error category. Useful for grouping in logs / metrics.
See Errors for the complete catalog.
Content negotiation
Every request body is application/json. Every response body is
application/json. The only exception is POST /v1/users/me/avatar, which
accepts multipart/form-data.
Idempotency
The SDK does not implement an Idempotency-Key header. Retries are safe for:
- All
GETrequests POST /v1/auth/logout(no-op if already logged out)DELETEof an already-revoked entityPOST /v1/auth/mfa/disable(idempotent)
Retries are NOT safe for:
POST /v1/auth/login— every call increments rate-limit + audit countersPOST /v1/auth/mfa/challenge— single-usemfa_tokenPOST /v1/auth/password/reset— single-use token
Cookies set by the SDK
| Cookie | Set by | Scope | Lifetime |
|---|---|---|---|
identsphere_at | register / login / refresh / passkey | Path=/, HttpOnly | access_expiry_secs |
identsphere_rt | register / login / refresh / passkey | Path={route_prefix}, HttpOnly | refresh_cookie_max_age_secs |
identsphere_csrf | register / login / refresh / passkey | Path=/, not HttpOnly | matches access token |
identsphere_trust | POST /v1/auth/trusted-browsers | Path={route_prefix}, HttpOnly | 30 days |
All cookies carry SameSite=Lax and Secure if cookies_secure = true.