Session Architecture
Storage
Sessions are stored in the database, not in JWTs: Benefits:- Can be revoked instantly
- Track session metadata (IP, user agent)
- No token size limits
- More secure (no client-side storage)
session- Team member sessionsclient_session- Client portal sessions
Session Lifecycle
Creation
Sessions are created when a user signs in:Validation
On every request, the session is validated:1
Extract Token
Session token read from HTTP-only cookie
2
Database Lookup
Query
session table for matching token3
Check Expiry
Verify
expiresAt is in the future4
Load User
Join with
user table to get user data5
Return Session
Return session object with user data
Refresh
Sessions are automatically refreshed on activity:- If session is older than 1 day, it’s refreshed
updatedAttimestamp updatedexpiresAtextended by 7 days- User stays logged in without re-authentication
Expiry
Sessions expire automatically:- Team sessions: 7 days from last activity
- Client sessions: 30 days from last activity
- Expired sessions are periodically purged from database
- Better Auth handles this automatically
Revocation
Sessions can be revoked (sign out):- Session record deleted from database
- Cookie cleared
- User redirected to sign-in page
Server-Side Session Access
In Server Components
In API Routes
In Server Actions
Client-Side Session Access
Using React Hook
Session Object Structure
Session Security
HTTP-Only Cookies
Session tokens are stored in HTTP-only cookies: Benefits:- Not accessible via JavaScript
- Protected from XSS attacks
- Automatically sent with requests
- Secure flag in production (HTTPS only)
CSRF Protection
Better Auth includes built-in CSRF protection:- All state-changing requests require valid CSRF token
- Tokens are stored in separate cookie
- Automatically validated on each request
Session Metadata
CharleOS tracks additional session metadata:| Field | Purpose |
|---|---|
ipAddress | Track IP for security audits |
userAgent | Identify device/browser |
createdAt | When session was created |
updatedAt | When session was last refreshed |
Multi-Device Sessions
Users can be signed in on multiple devices:Revoking All Sessions
Client Portal Sessions
Client portal sessions work identically but:- Use
client_sessiontable - Longer expiry (30 days vs 7 days)
- Separate cookie (
client_auth.session_token)
Session Management UI
Current Session Info
Sign Out Button
Troubleshooting
Session Not Persisting
Symptoms:- User signed in but immediately signed out
- Cookies not being set
BETTER_AUTH_URLdoesn’t match actual URL- HTTPS/domain mismatch
- Browser blocking cookies
- Verify
.env.localhas correct URL - Check browser console for cookie warnings
- Clear cookies and try again
Session Expired Too Quickly
Symptoms:- User signed out before 7 days
- Session not being refreshed
updateAgetoo long
- Check
session.updateAgeinlib/auth.ts - Ensure user is making requests (refreshes session)
Multiple Sign-Outs Required
Symptoms:- User signs out but still sees authenticated state
- Client-side cache not cleared
- SWR still holding session data
Best Practices
Always Validate Sessions Server-Side
Always Validate Sessions Server-Side
Never trust client-side session state:
Use HTTP-Only Cookies
Use HTTP-Only Cookies
Implement Activity-Based Expiry
Implement Activity-Based Expiry
Sessions should expire after inactivity:
Track Session Metadata
Track Session Metadata
Store IP and user agent for security:
- Helps identify suspicious activity
- Useful for security audits
- Better Auth stores this automatically