9.1 KiB
Session Handling Analysis for Horizontal Scaling
Executive Summary
✅ YES, your application is STATELESS and ready for horizontal scaling with load balancers.
The session handling architecture is designed to work across multiple gateway instances without requiring sticky sessions or shared in-memory storage. Users will NOT lose their sessions when API calls hit different gateway instances.
Architecture Overview
Backend Session Management (Gateway)
1. JWT Token-Based Authentication
- Location:
gateway/modules/auth/authentication.py - Token Storage: JWT tokens are stored in httpOnly cookies (
auth_tokenandrefresh_token) - Token Format: Self-contained JWT tokens with claims including:
sub(username)userIdmandateIdjti(token ID)sid(session ID)authenticationAuthorityexp(expiration)
2. Database-Backed Token Validation
-
Location:
gateway/modules/interfaces/interfaceDbAppObjects.py -
Token Table: All tokens are stored in a
Tokendatabase table with fields:id(jti - token ID)userIdauthoritysessionIdmandateIdstatus(ACTIVE/REVOKED)expiresAtrevokedAt,revokedBy,reason
-
Validation Process (per request):
- JWT token is extracted from httpOnly cookie or Authorization header
- Token is decoded and validated (signature, expiration)
- Token ID (
jti) is extracted from the JWT payload - Database query is performed to verify:
- Token exists in database
- Token status is ACTIVE
- Token matches user, session, and mandate context
- User is retrieved from database based on token claims
Key Code Reference (gateway/modules/auth/authentication.py:141-191):
# For LOCAL gateway JWTs, enforce DB-backed token validity and revocation
if tokenId:
db_tokens = dbApp.getRecordset(Token, recordFilter={"id": tokenId})
if db_tokens:
db_token = db_tokens[0]
token_authority = str(db_token.get("authority", "")).lower()
if token_authority == str(AuthAuthority.LOCAL.value):
# Must be active and match user/session/mandate
active_token = appInterface.findActiveTokenById(
tokenId=tokenId,
userId=user.id,
authority=AuthAuthority.LOCAL,
sessionId=sessionId,
mandateId=str(mandateId) if mandateId else None,
)
if not active_token:
raise credentialsException
3. No In-Memory Session Storage
- ✅ No Redis - No Redis or similar caching layer found
- ✅ No Memcached - No memcached usage found
- ✅ No In-Memory Sessions - All session state is in the database
- ✅ Stateless Design - Each request is independently validated
4. Session Management
- Session ID: Generated on login (
uuid.uuid4()) and stored in:- JWT token claim (
sid) - Token database record (
sessionId)
- JWT token claim (
- Logout: Revokes all tokens for a session by updating database records (sets
status=REVOKED) - Token Refresh: Creates new tokens and stores them in database
Key Code Reference (gateway/modules/routes/routeSecurityLocal.py:92-131):
# Create session id and include in token claims for session-scoped logout
session_id = str(uuid.uuid4())
token_data["sid"] = session_id
# Create access token + set cookie
access_token, _access_expires = createAccessToken(token_data)
setAccessTokenCookie(response, access_token)
# Save access token to database
token = Token(
id=jti,
userId=user.id,
authority=AuthAuthority.LOCAL,
tokenAccess=access_token,
tokenType="bearer",
expiresAt=expires_at.timestamp(),
sessionId=session_id,
mandateId=str(user.mandateId)
)
userInterface.saveAccessToken(token)
Frontend Session Management
1. Cookie-Based Token Storage
- Location:
frontend_agents/public/js/security/auth.jsandfrontend_agents/public/js/shared/apiCalls.js - Storage Method: Tokens are stored in httpOnly cookies (not localStorage or sessionStorage)
- Automatic Transmission: Cookies are automatically sent with requests using
credentials: 'include'
Key Code Reference (frontend_agents/public/js/shared/apiCalls.js:151-153):
// Note: With httpOnly cookies, we don't need to manually add Authorization header
// The browser automatically includes cookies with credentials: 'include'
2. CSRF Token Storage
- Location:
sessionStorage(client-side only) - Purpose: CSRF protection, not session state
- Note: CSRF tokens can be regenerated if lost, so this doesn't affect session persistence
Horizontal Scaling Compatibility
✅ Fully Compatible - No Issues
Why It Works:
-
Stateless Backend
- Each gateway instance validates tokens independently
- No shared in-memory state between instances
- All state is in the shared database
-
Database as Single Source of Truth
- Token validation queries the database on every request
- Token revocation updates the database
- All instances see the same token state
-
Cookie-Based Tokens
- Cookies are sent by the browser to whichever instance handles the request
- No server-side session storage needed
- Load balancer doesn't need sticky sessions
-
JWT Self-Contained Claims
- Token contains all necessary user context
- Database validation ensures token hasn't been revoked
- No need to look up session state from another instance
Load Balancer Configuration
Recommended Settings:
- ✅ Session Affinity: NOT REQUIRED (can use round-robin or least-connections)
- ✅ Health Checks: Standard HTTP health checks
- ✅ Cookie Handling: No special configuration needed (browser handles cookies automatically)
Potential Considerations
1. Database Connection Pooling
- Ensure each gateway instance has proper database connection pooling
- Database should handle concurrent connections from multiple instances
- Status: ✅ Should work fine if database is configured for multiple connections
2. CSRF Token Regeneration
- CSRF tokens stored in
sessionStoragemay be lost if user switches instances - Impact: Minimal - CSRF tokens are regenerated automatically
- Code Reference:
frontend_agents/public/js/shared/apiCalls.js:186-203handles CSRF token generation
3. Token Refresh Race Conditions
- If multiple requests refresh tokens simultaneously, ensure database handles concurrent updates
- Status: ✅ Current implementation uses database transactions (via
saveAccessToken)
4. Cookie Domain and Path
- Ensure cookies are set with correct domain/path for load balancer
- Current Settings (
gateway/modules/auth/jwtService.py:58-66):path="/"✅samesite="strict"✅httponly=True✅secure(based on HTTPS) ✅
Testing Recommendations
1. Multi-Instance Test
- Deploy 2+ gateway instances behind a load balancer
- Login on one instance
- Make requests that hit different instances
- Verify session persists across instances
2. Token Revocation Test
- Login on instance A
- Logout on instance B
- Verify token is revoked (cannot make requests on instance A)
3. Concurrent Request Test
- Make multiple simultaneous requests
- Verify all requests succeed regardless of which instance handles them
4. Database Connection Test
- Monitor database connections from multiple instances
- Verify connection pooling works correctly
- Check for connection leaks
Summary
| Aspect | Status | Notes |
|---|---|---|
| Stateless Backend | ✅ YES | No in-memory session storage |
| Database-Backed | ✅ YES | All token state in database |
| Cookie-Based | ✅ YES | httpOnly cookies, auto-sent by browser |
| Load Balancer Ready | ✅ YES | No sticky sessions needed |
| Horizontal Scaling | ✅ READY | Can scale to multiple instances |
Conclusion
Your application is fully ready for horizontal scaling. The session handling architecture is stateless and database-backed, which means:
- ✅ Users will NOT lose sessions when requests hit different instances
- ✅ Load balancer can use round-robin or least-connections (no sticky sessions needed)
- ✅ Token validation works independently on each instance
- ✅ Token revocation works across all instances (via database)
The only shared state is in the database, which you've confirmed will be a single logical instance. This is the correct architecture for horizontal scaling.
Files Analyzed
Backend
gateway/modules/auth/authentication.py- Token validationgateway/modules/auth/jwtService.py- JWT creation and cookie managementgateway/modules/routes/routeSecurityLocal.py- Login/logout endpointsgateway/modules/interfaces/interfaceDbAppObjects.py- Token database operationsgateway/modules/datamodels/datamodelSecurity.py- Token data model
Frontend
frontend_agents/public/js/security/auth.js- Authentication logicfrontend_agents/public/js/shared/apiCalls.js- API calls with cookie handling
Analysis Date: 2025-01-27 Analyzed by: AI Assistant