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: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
Related Documentation
Authentication
Auth architecture overview
Better Auth
Auth configuration details
Permissions
Role-based access control