CORS Preflight Fix - Final Implementation

Issue

OPTIONS preflight requests were returning 401 Unauthorized, causing:

Access to fetch at 'https://api.engram.work/api/v1/memory/episodes/...' 
from origin 'https://engram.work' has been blocked by CORS policy: 
Response to preflight request doesn't pass access control check: 
No 'Access-Control-Allow-Origin' header is present on the requested resource.

Root Cause

The CORSPreflightMiddleware was passing through to call_next(), which allowed authentication dependencies to be evaluated before CORS headers could be set. Even though FastAPI’s CORSMiddleware should handle OPTIONS automatically, route dependencies (like get_current_user) were being evaluated, causing 401 errors.

Solution

Updated CORSPreflightMiddleware to:

  1. Return immediately for OPTIONS requests (don’t call call_next())
  2. Validate origin against allowed origins list
  3. Set CORS headers directly in the response
  4. Bypass authentication completely for OPTIONS

Implementation

async def dispatch(self, request: Request, call_next):
    if request.method == "OPTIONS":
        origin = request.headers.get("origin")
        
        # Validate origin
        allowed_origins = self.settings.cors_origins
        is_allowed = origin in allowed_origins or "*" in allowed_origins
        
        # Create response with CORS headers
        response = Response(status_code=200)
        if is_allowed and origin:
            response.headers["Access-Control-Allow-Origin"] = origin
            response.headers["Access-Control-Allow-Credentials"] = "true"
        
        response.headers["Access-Control-Allow-Methods"] = "..."
        response.headers["Access-Control-Allow-Headers"] = "..."
        
        return response  # Return immediately, bypassing authentication
    
    response = await call_next(request)
    return response

Middleware Order

In FastAPI, middleware runs in reverse order of addition:

  1. CORSMiddleware (added first) → runs LAST
  2. CORSPreflightMiddleware (added second) → runs BEFORE CORSMiddleware

This means CORSPreflightMiddleware intercepts OPTIONS first and returns immediately, preventing authentication from being evaluated.

Testing

After deployment, test with:

curl -v -X OPTIONS \
  -H "Origin: https://engram.work" \
  -H "Access-Control-Request-Method: GET" \
  -H "Access-Control-Request-Headers: authorization" \
  https://api.engram.work/api/v1/memory/episodes/session-test

Expected: 200 OK with Access-Control-Allow-Origin: https://engram.work

Status

✅ Fix committed: 851e66be2
⏳ Waiting for deployment to complete
📝 Will test after deployment