Session Management
Sessions represent an authenticated user's connection to your application. This guide covers the full session lifecycle, configurable timeouts, concurrent session handling, and revocation patterns.
Session Lifecycle
A session begins when a user successfully authenticates and ends when they log out, their tokens expire, or the session is revoked. Here's how a session flows from creation to termination:
- 1User submits credentials (email + password, optionally MFA). On success, a server-side session record is created.
- 2An access token (15min default) and refresh token (7d default) are issued. Both are tied to the session ID.
- 3The client uses the access token for API requests. When it expires, the refresh token is exchanged for a new token pair.
- 4Each refresh rotates the refresh token (old one is invalidated) and resets the idle timeout timer.
- 5The session ends when: the user logs out, the refresh token expires without renewal, the idle timeout fires, or an admin revokes it.
┌──────────┐ ┌──────────────────┐ ┌──────────────┐
│ LOGIN │──────▶│ SESSION CREATED │──────▶│ TOKENS ISSUED│
└──────────┘ └──────────────────┘ └──────┬───────┘
│
┌───────────────────────┘
▼
┌─────────────────────┐
│ CLIENT USES ACCESS │◀──────────────────┐
│ TOKEN FOR REQUESTS │ │
└──────────┬──────────┘ │
│ (token expires) │
▼ │
┌─────────────────────┐ ┌─────────────┴──────┐
│ REFRESH TOKEN │───▶│ NEW TOKEN PAIR │
│ EXCHANGE │ │ (old refresh dead) │
└──────────┬──────────┘ └────────────────────┘
│ (refresh expired / idle timeout / logout)
▼
┌─────────────────────┐
│ SESSION ENDED │
└─────────────────────┘Token Types & Lifetimes
Every session involves three time-bound components. Understanding how they interact is key to configuring session behavior for your use case.
Access Token
Short-lived JWT (default 900s / 15min). Verified locally by your backend using the EdDSA public key. Contains user claims: user ID, tenant ID, roles, permissions, session ID.
access_token_ttl: 900Refresh Token
Longer-lived opaque token (default 604800s / 7 days). Single-use with rotation — each use returns a new refresh token and invalidates the old one. Exchanged for a new token pair.
refresh_token_ttl: 604800Session Record
Server-side record (default 30d absolute timeout). Ties together all token pairs issued during the session. Stored in PostgreSQL + Redis for fast lookup.
absolute_timeout: 2592000Relationship: The access token is always shorter than the refresh token, which is always shorter than (or equal to) the session absolute timeout. If any one of these expires, the user must re-authenticate.
Configuring Session Settings
All session-related settings are configurable per tenant via the settings API. Update the session section to adjust token lifetimes, idle timeout, concurrent session limits, and absolute timeout.
/api/v1/settings🔒 AuthUpdate session configuration for your tenant.
{
"session": {
"access_token_ttl": 600,
"refresh_token_ttl": 259200,
"idle_timeout_seconds": 1800,
"max_concurrent_sessions": 3,
"absolute_timeout_seconds": 2592000
}
}Idle Timeout
When idle_timeout_seconds is greater than 0, sessions are automatically revoked if no token refresh occurs within the configured window. The timer resets on every successful refresh.
- •Active user: Refreshing tokens before expiry keeps the session alive indefinitely (up to absolute timeout).
- •Inactive user: If the user closes the browser and returns after idle_timeout has elapsed, their refresh token will be rejected with a
session_expirederror. - •Value of 0: Disables idle timeout entirely. Sessions only end via refresh token expiry, absolute timeout, or explicit revocation.
// Example: 30-minute idle timeout for compliance-sensitive apps
{
"session": {
"idle_timeout_seconds": 1800
}
}Important: Idle timeout is evaluated server-side at refresh time. If your client refreshes tokens proactively (e.g., 1 minute before access token expiry), the effective idle window for the user is idle_timeout_seconds minus your refresh margin. Plan accordingly.
Concurrent Session Limits
The max_concurrent_sessions setting controls how many active sessions a single user can maintain simultaneously. When a new login would exceed the limit, the oldest session is automatically revoked.
Common Scenarios
Limit = 1
Single-device only. Logging in from a new device immediately terminates the previous session. Use for high-security environments or subscription services preventing credential sharing.
Limit = 5
Reasonable multi-device setup. Allows laptop, phone, tablet, work desktop, and one additional device. The 6th login kicks the oldest session.
Limit = 0
Unlimited sessions. No automatic revocation on new login. Sessions only end via timeout or explicit revocation. Default for most applications.
/api/v1/settings🔒 AuthSet concurrent session limit (e.g., single-device mode).
{
"session": {
"max_concurrent_sessions": 1
}
}Enforcement behavior: When you lower the limit, existing excess sessions are NOT immediately revoked. The limit is enforced on the next login attempt. To immediately enforce, combine with the revoke-all endpoint.
Absolute Timeout
Regardless of activity, sessions expire after absolute_timeout_seconds. This forces re-authentication even for continuously active users — useful for high-security environments where periodic credential verification is required.
- •Default: 2592000 seconds (30 days). After 30 days, the session ends regardless of refresh activity.
- •High-security: Set to 86400 (24 hours) or 28800 (8 hours) for environments requiring daily or per-shift re-authentication.
- •Value of 0: Disables absolute timeout entirely. Sessions persist as long as the refresh token is renewed within its TTL and idle timeout hasn't fired.
// Example: Force re-authentication every 8 hours (healthcare/finance)
{
"session": {
"absolute_timeout_seconds": 28800,
"idle_timeout_seconds": 1800,
"refresh_token_ttl": 28800
}
}Note:When absolute_timeout is set, ensure refresh_token_ttl does not exceed it. If refresh_token_ttl is longer than absolute_timeout, the session will still end at absolute_timeout regardless of the refresh token's validity.
Revoking Sessions
Sessions can be revoked in three ways: a user logs out, a user revokes all their other sessions, or an admin revokes a specific session. All patterns invalidate associated tokens immediately.
User Logout (Revoke Current Session)
/api/v1/auth/logout🔒 AuthEnd the current session. Invalidates the access token and refresh token.
Revoke All Other Sessions
Useful when a user suspects their credentials have been compromised. This terminates all sessions except the current one.
/api/v1/sessions/revoke-all🔒 AuthRevoke all sessions except the current one.
{
"exclude_current": true
}Admin: Revoke a Specific Session
Admins with sessions:deletepermission can revoke any user's session by ID. Use when investigating suspicious activity or responding to a security incident.
/api/v1/sessions/:id🔒 AuthRevoke a specific session by ID (admin action).
Refresh Token Rotation & Reuse Detection
Vyntech Account implements automatic refresh token rotation with reuse detection. Every time a refresh token is exchanged, a new one is issued and the old one is immediately invalidated. This is the default behavior — no configuration needed.
How It Works
- •Each refresh token is single-use. After exchange, it becomes invalid.
- •The new refresh token inherits the remaining TTL of the session (not a fresh 7-day window).
- •If a previously-used refresh token is submitted again (reuse), the entire session family is invalidated — all tokens associated with that session are revoked.
- •This protects against token theft: if an attacker steals a refresh token and uses it, the legitimate user's next refresh attempt triggers family invalidation, alerting both parties.
Normal Flow: Client → refresh_token_1 → Server Server → access_token_2 + refresh_token_2 (refresh_token_1 invalidated) Client → refresh_token_2 → Server Server → access_token_3 + refresh_token_3 (refresh_token_2 invalidated) Theft Detection: Attacker steals refresh_token_1 Legitimate client → refresh_token_1 → Server → new tokens (refresh_token_1 invalidated) Attacker → refresh_token_1 → Server → REUSE DETECTED! Server → entire session invalidated (all tokens revoked) Both parties must re-authenticate
Automatic protection: Refresh token rotation and reuse detection are always active. There is no setting to disable them. This provides defense-in-depth against token theft without any implementation effort on your side.
Best Practices
Set idle timeout for compliance-sensitive apps
If your app handles sensitive data (healthcare, finance, government), set idle_timeout_seconds to 1800 (30 minutes) or less. This satisfies common compliance frameworks (HIPAA, PCI-DSS, SOC 2) that require automatic session termination after inactivity.
Keep access tokens short (300–900s)
Access tokens are verified locally without a network call. If one is compromised, it remains valid until expiry. Shorter lifetimes (5–15 minutes) limit the damage window. For high-security scenarios, use 300s (5 minutes).
Use concurrent session limits to prevent credential sharing
If your business model requires per-user licensing, set max_concurrent_sessions to a reasonable number (1–3). Users sharing credentials will constantly kick each other out, naturally discouraging the behavior.
Implement proper token storage
For web apps, store tokens in httpOnly, Secure, SameSite=Strict cookies — never localStorage. For mobile apps, use platform secure storage (iOS Keychain, Android Keystore). This prevents XSS-based token theft.
Refresh proactively, not reactively
Don't wait for a 401 response to trigger a refresh. Instead, refresh 1–2 minutes before access token expiry. This avoids failed requests and provides a smoother user experience. Use the expires_in field from the token response to schedule refreshes.
What's Next
Sessions API →
Full reference for listing, inspecting, and revoking sessions.
Authentication Flows →
Visual diagrams showing where sessions fit in the auth lifecycle.
Risk Engine Guide →
How session anomalies feed into the risk scoring system.
IP Access Control Guide →
Restrict sessions by IP address with allowlists and blocklists.