Session Upgrade
JWT tokens are ideal for REST APIs but add overhead to high-frequency socket communication. Altruist provides a session upgrade flow: login with JWT over HTTP, then upgrade to a lightweight session token for real-time connections.
The Flow
Loading diagram...
| Step | What Happens | Token |
|---|---|---|
| 1 | Login via HTTP | JWT issued |
| 2 | Upgrade via HTTP | Session token issued, JWT invalidated |
| 3 | Connect to socket | Session token as Bearer |
Setup
1. Auth Controller (provides login + upgrade)
[ApiController]
[Route("/auth")]
public class AuthController : JwtAuthController
{
public AuthController(
IJwtTokenValidator validator,
ILoginService loginService,
TokenSessionSyncService syncService,
IJwtTokenIssuer issuer,
IAuthService authService,
ILoggerFactory loggerFactory)
: base(validator, loginService, syncService, issuer, authService, loggerFactory)
{
}
}
2. Game Portal (protected with SessionShield)
[Portal("/game")]
[SessionShield]
public class GamePortal : AltruistPortal
{
[Gate("move")]
public async Task OnMove(MovePacket packet, string clientId)
{
// Only clients with valid session tokens reach here
}
}
3. Client Flow
# Step 1: Login → get JWT
curl -X POST http://localhost:3000/auth/login/unamepwd \
-H "Content-Type: application/json" \
-d '{"username": "hero", "password": "secret123"}'
# → { "accessToken": "eyJ...", "refreshToken": "eyJ..." }
# Step 2: Upgrade JWT → get session token
curl -X POST http://localhost:3000/auth/upgrade \
-H "Authorization: Bearer eyJ..." \
-H "Content-Type: application/json" \
-d '{"token": "eyJ..."}'
# → { "accessToken": "31c7e8ef-...;session", "refreshToken": "eef813a8-..." }
# Step 3: Connect to socket with session token
# WebSocket: ws://localhost:3000/ws with Authorization: Bearer 31c7e8ef-...
# TCP: send session token in initial handshake
Session Token Response
{
"accessToken": "31c7e8ef-1541-4499-b2a9-577b80c160f1;session",
"refreshToken": "eef813a8-714a-43ed-82d9-41fdb832cd1c;session",
"accessExpiration": "2025-04-16T21:14:42Z",
"refreshExpiration": "2025-04-23T20:14:42Z"
}
Why Upgrade?
| JWT | Session Token | |
|---|---|---|
| Validation | Decode + verify signature (CPU-heavy) | Cache lookup (fast) |
| Size | ~800+ bytes | ~40 bytes (UUID) |
| Revocation | Difficult (stateless) | Instant (delete from cache) |
| Best for | HTTP REST APIs | High-frequency socket messages |
Note:
Session tokens are validated via a cache lookup — no cryptographic verification on every packet. For a game server processing thousands of packets per second, this is significantly faster than JWT validation.
Hooks
Override hooks on JwtAuthController for custom logic:
protected override UpgradeAuthRequest OnUpgrade(UpgradeAuthRequest context, string clientId)
{
// Modify context before upgrade
return context;
}
protected override async Task OnUpgradeSuccess(UpgradeAuthRequest context, string clientId, IIssue issue)
{
// Create game session, load player data, etc.
}
protected override async Task OnUpgradeFailed(UpgradeAuthRequest context, string clientId)
{
// Log failed upgrade attempt
}
Config
altruist:
security:
mode: "jwt"
key: "your-base64-secret-key"
persistence:
cache:
provider: redis # Session tokens stored in cache (redis recommended for production)
Note:
Session tokens are stored in the cache provider. Use Redis for production — inmemory cache loses all sessions on server restart.