JWT Middleware Pipeline
Middleware Execution Order
JWT Validation Steps
Step 1: Token Extraction- Invalid signature →
SecurityTokenInvalidSignatureException→ 401 - Wrong issuer →
SecurityTokenInvalidIssuerException→ 401 - Wrong audience →
SecurityTokenInvalidAudienceException→ 401 - Expired token →
SecurityTokenExpiredException→ 401
User Synchronization
Automatic Sync Trigger
Every authenticated controller action calls:EnsureUserExistsAsync Implementation
Sync Characteristics
Performance: ~5-15ms (indexed UPSERT) Idempotency: Safe to call multiple times Failure Handling: Logged as warning, request continues Timing: Synchronous (awaited before proceeding) Frequency: Every authenticated requestSupabase Integration
JWT Issuer Validation
Supabase issues JWTs with specific issuer format:Service Role vs Anon Key
Client-Side (Supabase Anon Key):- Full database access (no RLS restrictions)
- Perform UPSERT operations
- Read all tables regardless of RLS policies
- Backend implements authorization in application code
Authorization vs Authentication
Authentication
Question: “Who are you?” Mechanism: JWT validation via middleware Result:User principal populated with claims
Happens: Before controller method execution
Authorization
Question: “Are you allowed to do this?” Mechanism: Custom logic in controller Example:[Authorize] Attribute
[AllowAnonymous] Attribute
/health/api/health/api/ping/api/settings/feature-flag/{key}/api/speech/generate
Token Lifecycle
Token Acquisition (Client)
Token Usage
Token Expiration
Access Token: Expires after 1 hour Detection:Token Refresh
Security Considerations
JWT Secret Protection
Environment Variable:HTTPS Requirement
JWTs transmitted inAuthorization header (plaintext over HTTP).
Development: HTTP acceptable (localhost)
Production: HTTPS mandatory
Why: Bearer tokens are susceptible to man-in-the-middle attacks over HTTP
Token Revocation
Limitation: JWTs cannot be revoked before expiration Mitigation: Short expiry (1 hour) Workaround: Track revoked tokens in database (not currently implemented)Supabase Auth Events
Not Used: DualMind doesn’t listen to Supabase auth webhooks User Deletion: Deleting user in Supabase doesn’t cascade to DualMind database Implication: Orphaned user records possible if user deleted from Supabase Auth Future: Implement webhook listener foruser.deleted event
Development vs Production
Development Mode
JWT_SECRET: May be missing (validation skipped with warning) CORS: Allows all origins HTTPS: Not enforced Logging: Verbose request/response loggingProduction Mode
JWT_SECRET: MUST be set (validation enforced) CORS: Configured allowed origins only HTTPS: Enforced at infrastructure level Logging: Error-level only (no verbose logging)Troubleshooting
401 Unauthorized
Causes:- Missing
Authorizationheader - Invalid JWT signature (wrong
JWT_SECRET) - Expired token (
exp< now) - Wrong issuer (Supabase URL mismatch)
- Wrong audience (
aud != "authenticated")
403 Forbidden
Causes:- Valid JWT but accessing resource owned by different user
- Private thread accessed by non-owner
thread.user_id vs JWT sub claim
User Sync Failures
Symptom: Warnings in logs but requests succeed Causes:- Database connectivity issue
- Invalid user_id format (not UUID)
- Supabase service role key incorrect
Next Steps
Request Lifecycle
Where JWT validation fits in execution flow
System Invariants
Authentication-related invariants