Sessions & Token Rotation
When a user logs in to an application powered by Auris, the system creates a session. This session is the authoritative record of the user’s authenticated state. Understanding how sessions work, how tokens rotate, and how Auris detects token theft is essential for building secure applications and troubleshooting authentication issues.
What Is a Session in Auris?
A session in Auris is a server-side record stored in the database (via Prisma), not a client-side cookie or token. Each session contains:
| Field | Description |
|---|---|
id | Unique session identifier |
userId | The authenticated user |
sessionToken | An opaque token stored in an httpOnly cookie on the client |
accessToken | The most recently issued access token (JWT) |
refreshToken | The most recently issued refresh token (opaque string) |
tokenFamily | Identifier linking all refresh tokens in this session’s rotation chain |
createdAt | When the session was created (used for absolute expiry) |
lastActiveAt | When the session was last used (used for sliding expiry) |
expiresAt | When the session expires |
ipAddress | IP address from the original login |
userAgent | Browser/device identifier from the original login |
acr | Authentication Context Class Reference (the authentication strength level) |
amr | Authentication Methods Reference (which factors were used: password, otp, webauthn) |
The key distinction from many other auth providers: Auris sessions are server-authoritative. The server always knows which sessions exist, which are active, and can revoke any session instantly. There is no reliance on token expiry alone for session termination.
Session Lifecycle
A session moves through a well-defined lifecycle from creation to termination:
Session Creation
When authentication succeeds (after all factors including MFA, adaptive risk checks, and Actions Engine hooks), Auris:
- Creates an
OAuthSessionrecord in the database - Generates a random
sessionTokenand sets it as anhttpOnlycookie (30-minute TTL, refreshed on each use) - Issues an access token (signed JWT) with the user’s claims, roles, and any custom claims
- Issues a refresh token (opaque
rt_prefixed string) - Assigns a
tokenFamilyidentifier that links all future refresh tokens in this session
Active Use
During the session’s active lifetime, the client sends the access token on every API request. The resource server validates the JWT signature locally (via JWKS) without contacting Auris. No database lookup occurs for access token validation, which keeps latency low.
Refresh
When the access token expires, the client sends the refresh token to the token endpoint. Auris:
- Looks up the refresh token in the database
- Validates that it has not been used before (rotation check)
- Validates that the session has not expired (absolute and sliding checks)
- Invalidates the old refresh token (marks it as used)
- Issues a new access token and a new refresh token
- Updates
lastActiveAton the session (resets the sliding window)
Termination
Sessions terminate through several mechanisms, each designed for a different scenario:
| Mechanism | When It Happens | Effect |
|---|---|---|
| Explicit logout | User clicks “Sign Out” | Session deleted, all tokens for this session invalidated |
| Sliding expiry | No refresh within the inactivity window | Session expires, next refresh attempt fails with SESSION_EXPIRED |
| Absolute expiry | Session has been alive longer than the absolute maximum | Session expires regardless of activity |
| Admin revocation | Admin revokes session from Console | Session deleted immediately |
| Reuse detection | An already-used refresh token is presented | Entire token family revoked (see below) |
| Account action | User disabled, deleted, or password changed | All sessions for the user are revoked |
Refresh Token Rotation
Refresh token rotation is a security mechanism where every successful token refresh invalidates the old refresh token and issues a new one. Auris implements rotation by default with no opt-out.
Why Rotate?
Without rotation, a stolen refresh token remains valid until its natural expiry (7 days by default). The attacker can use it to obtain new access tokens indefinitely within that window, even if the legitimate user continues using the application.
With rotation, a stolen refresh token can only be used once. If the legitimate user refreshes first (which is the common case), the stolen token becomes invalid. If the attacker refreshes first, the legitimate user’s next refresh attempt triggers reuse detection.
How It Works
Each refresh token in Auris is stored in the database with the following metadata:
{
token: "rt_7fKp2mXa9qN3vB8yR4tL1wC6jD5sE0uH",
tokenFamily: "fam_abc123",
used: false,
createdAt: "2025-02-10T08:15:00Z",
sessionId: "sess_xyz789"
}When a refresh request arrives:
- Token lookup: Find the refresh token in the database
- Used check: If
used: true, this is a reuse attempt (see Reuse Detection) - Mark as used: Set
used: trueon the current token - Issue new tokens: Create a new refresh token with the same
tokenFamilyandused: false - Return: Send the new access token + refresh token to the client
// Request
POST /api/auth/token
{
"grant_type": "refresh_token",
"refresh_token": "rt_7fKp2mXa9qN3vB8yR4tL1wC6jD5sE0uH"
}
// Response
{
"ok": true,
"data": {
"accessToken": "eyJhbGciOiJSUzI1NiJ9...",
"refreshToken": "rt_NEW_rotated_token_here...",
"expiresIn": 900
}
}The client must always store and use the latest refresh token returned from the token endpoint. If the client fails to update its stored refresh token (for example, due to a network error after the response was sent), the old token is already marked as used. The next refresh attempt will trigger reuse detection and revoke the entire session. SDKs handle this automatically, but custom integrations must be careful to persist the new token before discarding the old one.
Refresh Token Reuse Detection
Reuse detection is the mechanism that catches token theft. If an already-used refresh token is presented to the token endpoint, Auris assumes the token was stolen and takes defensive action.
The Attack Scenario
- User Alice logs in. She receives refresh token
RT-1. - Attacker steals
RT-1(via XSS, network interception, or device compromise). - Case A: Alice refreshes first.
RT-1is marked as used. She receivesRT-2. Later, the attacker tries to useRT-1. Auris seesRT-1is already used. Reuse detected. - Case B: Attacker refreshes first.
RT-1is marked as used. Attacker receivesRT-2a. Later, Alice tries to useRT-1. Auris seesRT-1is already used. Reuse detected.
In both cases, Auris knows something is wrong because a used token was presented.
What Happens on Reuse Detection
When reuse is detected, Auris revokes the entire token family:
- Every refresh token with the same
tokenFamilyis invalidated - The session associated with the family is terminated
- An audit log entry is created with
action: 'TOKEN_REUSE_DETECTED' - If the user has notification preferences set, a suspicious login notification is sent
Both the legitimate user and the attacker are logged out. The legitimate user must re-authenticate. This is an intentional security tradeoff: a brief inconvenience for the user is preferable to allowing a stolen token to continue being used.
Token Families and Session Binding
A token family is a chain of refresh tokens linked to a single session. When a session is created, a unique tokenFamily identifier is generated. Every refresh token issued within that session shares the same family ID.
Session created → tokenFamily: "fam_abc123"
└─ RT-1 (fam_abc123) → used → RT-2 (fam_abc123) → used → RT-3 (fam_abc123) → activeToken families serve two purposes:
- Reuse detection scope: When a reused token is detected, Auris can identify and revoke all tokens in the family, not just the individual token.
- Session correlation: All tokens in a family trace back to the same session and the same original authentication event. This makes audit trails coherent.
A user can have multiple active token families — one per device/session. Revoking one family does not affect other families for the same user.
Absolute vs Sliding Expiry
Auris supports two expiry models for sessions, and both can be active simultaneously:
Sliding Expiry (Inactivity Timeout)
The session expires if the user does not refresh their tokens within a configured window. Each successful refresh resets the sliding timer.
- Default: 7 days of inactivity
- Use case: Log out inactive users automatically
- Behavior:
lastActiveAtis updated on each refresh. Ifnow - lastActiveAt > slidingWindow, the session is expired.
Absolute Expiry (Maximum Session Lifetime)
The session expires after a fixed duration from creation, regardless of activity.
- Default: 30 days from session creation
- Use case: Force re-authentication periodically for security compliance
- Behavior:
now - createdAt > absoluteMaxtriggers expiry, even if the user has been continuously active
Configuration
Both values are configured in the Auris Console under Settings → Security → Session Policies:
| Setting | Description | Default |
|---|---|---|
| Sliding Expiry | Maximum inactivity before session expires | 7 days |
| Absolute Expiry | Maximum session lifetime from creation | 30 days |
| Refresh Token Lifetime | How long a single refresh token is valid (must be ≤ sliding expiry) | 7 days |
When both are configured, the session expires at whichever comes first. For example, with a 7-day sliding window and 30-day absolute max:
- A user who is active daily will be logged out after 30 days and must re-authenticate
- A user who stops using the application will be logged out after 7 days of inactivity
For highly sensitive applications (banking, healthcare), consider setting absolute expiry to 8-24 hours. This forces frequent re-authentication regardless of activity, reducing the risk window if a session is compromised.
Multi-Device Sessions
Each device or browser where a user logs in creates a separate, independent session. Sessions are not shared across devices.
How It Works
- Alice logs in on her laptop. Session S1 is created with token family F1.
- Alice logs in on her phone. Session S2 is created with token family F2.
- Alice logs in on a shared computer. Session S3 is created with token family F3.
Each session has its own:
- Session record in the database
- Token family
- Independent expiry timers (sliding and absolute)
- Independent refresh token rotation chain
Session Management
Users can view and manage their active sessions via the account security page. Administrators can manage sessions for any user in the Auris Console under Users → (select user) → Sessions.
Available actions:
| Action | Scope | Effect |
|---|---|---|
| Revoke single session | One device | Terminates the specific session; user must log in again on that device |
| Revoke all sessions | All devices | Terminates every session for the user across all devices |
| Revoke all other sessions | All devices except current | Useful when a user suspects account compromise: “Log me out everywhere else” |
Session Metadata
Each session stores metadata captured at creation time:
- IP Address: The IP from which the login occurred
- User Agent: The browser or client identifier
- Approximate Location: City/country derived from GeoIP (if suspicious login detection is enabled)
- Last Active: When the session was last used (refreshed)
This metadata is displayed in the Sessions list and helps users identify unfamiliar sessions.
Relationship Between Keycloak Sessions and Auris Sessions
Auris uses Keycloak as the underlying identity provider. When a user authenticates, two sessions exist:
Keycloak Session
The Keycloak session is created when the user authenticates against Keycloak (password verification, social login callback, SAML assertion). Keycloak manages its own session lifecycle, including SSO session cookies and realm-level session policies.
Auris Session
The Auris session is created after Keycloak authentication succeeds and all Auris-layer checks pass (Actions Engine, adaptive MFA, IP rules, CAPTCHA). The Auris session is the authoritative session for application access.
How They Relate
Key points:
- Keycloak sessions enable Single Sign-On (SSO) across applications within the same realm. If a user is already authenticated in Keycloak, they can obtain tokens for a second application without re-entering credentials.
- Auris sessions are per-application. Even if Keycloak SSO is active, each application the user accesses gets its own Auris session with its own token family.
- Revoking an Auris session does not revoke the Keycloak session (the user may still have SSO access to other applications). To fully sign out, the logout flow calls both Auris session revocation and Keycloak’s
end_session_endpoint. - Session policies configured in the Auris Console (sliding expiry, absolute expiry) apply to Auris sessions. Keycloak has its own session timeout settings configured at the realm level.
For most deployments, you only need to think about Auris sessions. The Keycloak session layer is transparent to applications using the Auris SDK. The dual-session architecture is relevant primarily when debugging SSO behavior across multiple applications or when configuring Keycloak realm settings directly.
Session Storage and Performance
Auris sessions are stored in PostgreSQL via Prisma. This design choice has important implications:
Durability: Sessions survive server restarts and deployments. Unlike in-memory session stores (Redis-only), database-backed sessions are not lost during infrastructure changes.
Scalability: PostgreSQL handles millions of session records efficiently. Indexes on sessionToken, userId, and tokenFamily ensure fast lookups.
Cleanup: Expired sessions are cleaned up by a periodic cron job (/api/oauth/cron/cleanup). This job deletes expired sessions and authorization codes, keeping the session table size manageable. The cron runs every 5 minutes via Vercel Cron.
Access token validation does not hit the database: Access tokens are JWTs verified locally using the public key from the JWKS endpoint. Only refresh token exchanges and session management operations require database queries.
Related Concepts
- Tokens Explained — JWT structure, signing algorithms, and storage best practices
- OAuth 2.0 & OIDC — The authorization framework that sessions operate within
- PKCE Flow — How authorization codes are exchanged for session tokens
- Adaptive MFA & Risk Scoring — How risk assessment affects session creation
- Security Settings — Configure session policies, brute-force protection, and IP rules