wiki/reviews/20260111 doc_session_handling_analysis.md
2026-01-11 13:07:11 +01:00

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_token and refresh_token)
  • Token Format: Self-contained JWT tokens with claims including:
    • sub (username)
    • userId
    • mandateId
    • jti (token ID)
    • sid (session ID)
    • authenticationAuthority
    • exp (expiration)

2. Database-Backed Token Validation

  • Location: gateway/modules/interfaces/interfaceDbAppObjects.py

  • Token Table: All tokens are stored in a Token database table with fields:

    • id (jti - token ID)
    • userId
    • authority
    • sessionId
    • mandateId
    • status (ACTIVE/REVOKED)
    • expiresAt
    • revokedAt, revokedBy, reason
  • Validation Process (per request):

    1. JWT token is extracted from httpOnly cookie or Authorization header
    2. Token is decoded and validated (signature, expiration)
    3. Token ID (jti) is extracted from the JWT payload
    4. Database query is performed to verify:
      • Token exists in database
      • Token status is ACTIVE
      • Token matches user, session, and mandate context
    5. 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)
  • 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

  • Location: frontend_agents/public/js/security/auth.js and frontend_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:

  1. Stateless Backend

    • Each gateway instance validates tokens independently
    • No shared in-memory state between instances
    • All state is in the shared database
  2. 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
  3. 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
  4. 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 sessionStorage may be lost if user switches instances
  • Impact: Minimal - CSRF tokens are regenerated automatically
  • Code Reference: frontend_agents/public/js/shared/apiCalls.js:186-203 handles 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)
  • 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:

  1. Users will NOT lose sessions when requests hit different instances
  2. Load balancer can use round-robin or least-connections (no sticky sessions needed)
  3. Token validation works independently on each instance
  4. 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 validation
  • gateway/modules/auth/jwtService.py - JWT creation and cookie management
  • gateway/modules/routes/routeSecurityLocal.py - Login/logout endpoints
  • gateway/modules/interfaces/interfaceDbAppObjects.py - Token database operations
  • gateway/modules/datamodels/datamodelSecurity.py - Token data model

Frontend

  • frontend_agents/public/js/security/auth.js - Authentication logic
  • frontend_agents/public/js/shared/apiCalls.js - API calls with cookie handling

Analysis Date: 2025-01-27 Analyzed by: AI Assistant