Session Management
AuthHero uses a dual-session architecture with Login Sessions and Sessions to handle authentication flows and user sessions. Understanding how these work together is crucial for developers working with the AuthHero authentication system.
Overview
- Login Sessions: Temporary sessions that track authentication flows (e.g., OAuth authorization, universal login)
- Sessions: Long-lived user sessions that persist across multiple applications and login flows
Login Sessions
Login sessions are temporary, short-lived sessions that track a specific authentication flow from start to finish.
Purpose
- Track OAuth authorization flows
- Store authentication parameters (client_id, redirect_uri, scope, etc.)
- Maintain state during multi-step authentication processes
- Handle CSRF protection via state parameters
Lifecycle
- Created when an authentication flow starts (e.g.,
/authorizeendpoint) - Updated as the flow progresses (e.g., linking to user sessions)
- Completed when authentication succeeds and tokens are issued
- Expired after a short time (typically 5-10 minutes)
Key Properties
id: Unique identifier (used as OAuthstateparameter)authParams: OAuth parameters (client_id, redirect_uri, scope, etc.)session_id: Reference to linked user session (optional)expires_at: Short expiration timecsrf_token: CSRF protection
Example
// Created during /authorize
const loginSession = {
id: "login_abc123",
authParams: {
client_id: "app123",
redirect_uri: "https://app.com/callback",
scope: "openid email profile",
},
session_id: null, // Initially not linked
expires_at: "2025-09-04T12:05:00Z", // 5 minutes from now
csrf_token: "csrf_xyz789",
};Sessions
Sessions are long-lived user sessions that persist across multiple applications and authentication flows.
Purpose
- Represent an authenticated user session
- Enable Single Sign-On (SSO) across applications
- Store session metadata (device info, last activity, etc.)
- Support session management (logout, revocation)
Lifecycle
- Created when a user successfully authenticates
- Reused for subsequent authentication flows (SSO)
- Updated when linked to new login sessions or applications
- Expired after inactivity or explicit logout
Key Properties
id: Unique session identifieruser_id: Reference to the authenticated userlogin_session_id: Reference to the login session that created this sessionclients: List of applications that have used this sessionexpires_at: Long expiration timedevice: Device and browser information
Example
// Created after successful authentication
const session = {
id: "session_def456",
user_id: "email|user123",
login_session_id: "login_abc123",
clients: ["app123"],
expires_at: "2025-09-11T12:00:00Z", // 7 days from now
device: {
last_ip: "192.168.1.1",
last_user_agent: "Mozilla/5.0...",
},
};Session Linking
The relationship between login sessions and sessions is dynamic and changes throughout authentication flows.
Initial Creation
When a user first authenticates:
- Login session is created for the OAuth flow
- User completes authentication (password, social, etc.)
- New session is created and linked to the login session
- Login session's
session_idis set to the new session'sid
Session Reuse (SSO)
When a user has an existing session:
- New login session is created for the OAuth flow
- System detects existing valid session (via cookie)
- Existing session is linked to the new login session
- No new session is created - the existing one is reused
Example Flow
First Login
1. GET /authorize → Creates login_session_1 (session_id: null)
2. User authenticates → Creates session_1 (login_session_id: login_session_1)
3. login_session_1 updated → (session_id: session_1)Subsequent Login (SSO)
1. GET /authorize → Creates login_session_2 (session_id: null)
2. System detects session_1 via cookie
3. login_session_2 updated → (session_id: session_1)
4. session_1 updated → (clients: [..., new_client])Implementation Patterns
Creating Sessions
Always create sessions linked to a login session:
// ✅ Correct
const session = await env.data.sessions.create("tenantId", {
id: "sessionId",
user_id: "email|userId",
login_session_id: loginSession.id, // Always link to login session
clients: ["clientId"],
// ... other fields
});Linking Existing Sessions
When reusing an existing session for a new login flow:
// Link existing session to new login session
await env.data.loginSessions.update("tenantId", loginSession.id, {
session_id: existingSession.id,
});
// Update session's client list if needed
await env.data.sessions.update("tenantId", existingSession.id, {
clients: [...existingSession.clients, newClientId],
});Authentication Response
Always pass the session ID to ensure session reuse:
return createFrontChannelAuthResponse(ctx, {
user,
authParams: loginSession.authParams,
client,
loginSession: { ...loginSession, session_id: existingSession.id },
sessionId: existingSession.id, // Ensures session reuse
});Security Considerations
CSRF Protection
- Login session IDs are used as OAuth
stateparameters - Prevents CSRF attacks during authentication flows
Session Hijacking
- Sessions are tied to device metadata
- IP address and user agent tracking
- Secure cookie settings
Session Expiration
- Login sessions: Short-lived (5-10 minutes)
- User sessions: Longer-lived (hours to days)
- Configurable expiration policies
Common Patterns
Universal Login Flow
- User visits
/authorize - Redirected to universal login (
/u/login/identifier) - User authenticates
- Session created and linked to login session
- User redirected back to application
Check Account Flow
- User has existing session (cookie)
- New authorization flow starts
- Redirected to
/u/check-account - Existing session linked to new login session
- Authentication completes without re-login
Silent Authentication
- Application checks authentication status
- Uses existing session if valid
- No user interaction required
- Tokens issued based on existing session
Debugging Tips
Finding Related Sessions
-- Find login session by state parameter
SELECT * FROM login_sessions WHERE id = 'state_parameter';
-- Find session linked to login session
SELECT s.* FROM sessions s
JOIN login_sessions ls ON s.id = ls.session_id
WHERE ls.id = 'state_parameter';
-- Find all sessions for a user
SELECT * FROM sessions WHERE user_id = 'email|user123';Common Issues
- Session not linked: Login session
session_idis null - Multiple sessions: User has multiple active sessions (normal for different devices)
- Session reuse failure: Existing session not properly linked to new login session
Best Practices
- Always link sessions: Every session should be created with a
login_session_id - Reuse existing sessions: Don't create new sessions if a valid one exists
- Update client lists: Add new clients to existing sessions when reusing
- Handle expiration: Implement proper session cleanup and renewal
- Security first: Always validate session ownership and device metadata