Sessions & refresh
A session in IdentSphere is a row in user_sessions plus a pair of cookies on
the client.
Tokens
| Token | Lifetime | Storage | Purpose |
|---|---|---|---|
| Access token | 15 min default | identsphere_at cookie + Authorization header | Authenticates every request. JWT with sub, org, email, aal, mfa_verified_at claims. |
| Refresh token | 30 days default | identsphere_rt cookie | Exchanged at /refresh for a new access token. Opaque; SHA-256 hashed in DB. |
| CSRF token | matches access TTL | identsphere_csrf cookie (not HttpOnly) | Double-submit pattern. |
Rotation
Refresh tokens rotate on every successful /refresh. The new refresh
token replaces the prior one in-place on the user_sessions row. A
replayed old refresh token finds no matching row → 401.
In a future version, replay detection will revoke the entire session family.
Revocation
Revocation is soft: the row's revoked flag is set to true. The
session-cache stores the revocation signal under
IdentSphere:session:revoked:{session_family_id} so the auth middleware sees
it on the next request without re-querying.
Revoke a session:
| Action | Endpoint |
|---|---|
| Sign out current | POST /v1/auth/logout |
| Sign out one specific | DELETE /v1/auth/sessions/:id |
| Sign out everywhere | DELETE /v1/auth/sessions |
| Sign out everywhere except current (e.g. after password change) | Use sign_out_other_sessions: true on POST /v1/users/me/password |
Listing
GET /v1/auth/sessions returns active sessions for the caller, marking
is_current: true for the one signing the request.
[
{
"id": "...",
"user_agent": "Mozilla/5.0 ...",
"ip_address": "203.0.113.42",
"last_active_at": "...",
"is_current": true,
"created_at": "..."
}
]
Session families
session_family_id groups related sessions. A single session family
covers a series of /refresh rotations — same browser, same login,
many access tokens over time. Revoking by family revokes the whole chain.
This is the unit of MFA step-up assertions: the step-up TTL is keyed per family.
Last-active tracking
The auth middleware bumps last_active_at on every authenticated request
(subject to a short debounce window to avoid one UPDATE per request in
hot paths).
DPoP (planned)
The schema already has dpop_thumbprint reserved. DPoP-bound sessions —
tokens that only validate when accompanied by a fresh per-request signature
from the binding keypair — are planned for a future release.
Idle vs absolute timeout
The SDK enforces only ABSOLUTE timeouts (access_expiry_secs,
refresh_expiry_secs). It doesn't enforce idle timeouts. If you want one,
implement it client-side or via a middleware that revokes sessions whose
last_active_at is older than your idle threshold.
CORS + cookies
Cookie auth across origins requires:
- Backend sends
Set-CookiewithSameSite=NoneandSecure(toggle viacookies_secure: true). - Frontend sends requests with
credentials: 'include'(oraxios.defaults.withCredentials = true). - CORS middleware allows credentials and lists the frontend origin
explicitly (no
*).