Skip to content

Conversation

@hammadtq
Copy link
Collaborator

Summary

This PR fixes a critical issue where CORS preflight requests (OPTIONS method) were being blocked by the JWT authentication middleware with 401 Unauthorized, preventing browser-based applications from accessing the gateway APIs.

Problem

  • CORS preflight requests failing: Browser requests to /mem/events, /a2a/tasks/send, and other endpoints were blocked
  • Root cause: JWT middleware was rejecting all OPTIONS requests that don't include Authorization headers
  • Impact: Demo2.html and other browser-based clients couldn't access the gateway APIs
  • Error pattern: OPTIONS /mem/events?limit=10 HTTP/1.1" 401 Unauthorized

Solution

Added OPTIONS method handling to middleware/auth.py to allow CORS preflight requests to pass through without authentication:

async def jwt_auth_mw(request: Request, call_next):
    # Skip authentication for OPTIONS requests (CORS preflight)
    if request.method == "OPTIONS":
        return await call_next(request)
    
    # ... existing authentication logic

Key Changes

  • middleware/auth.py: Added if request.method == "OPTIONS": check before JWT validation
  • Scope: Fixes both main.py (development) and attach-gateway (production) entry points
  • No breaking changes: Only affects OPTIONS requests, all other authentication remains unchanged

Testing

Before fix:

# Browser console errors
Access to fetch at 'http://localhost:8080/mem/events?limit=10' from origin 
'http://localhost:9000' 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.

After fix:

# Successful CORS preflight and actual requests
OPTIONS /mem/events?limit=10 HTTP/1.1" 200 OK
GET /mem/events?limit=10 HTTP/1.1" 200 OK

Test commands:

# Development mode
uvicorn main:app --host 0.0.0.0 --port 8080

# Production mode  
attach-gateway --port 8080

# Browser test
open http://localhost:9000/demo2.html

🔍 Technical Details

CORS Preflight Flow:

  1. Browser sends OPTIONS request (no Authorization header)
  2. Server responds with allowed methods/headers
  3. Browser sends actual request with Authorization header
  4. Server processes authenticated request

Previous behavior: Step 1 failed with 401
New behavior: Step 1 succeeds, Step 4 still requires authentication ✅

Verification

  • ✅ Demo2.html memory events load successfully
  • ✅ A2A task sending works from browser
  • ✅ Direct API calls with JWT still work
  • ✅ Non-OPTIONS requests still require authentication
  • ✅ Both main.py and attach-gateway behave identically

Impact

  • Browser compatibility: Full CORS support for web applications
  • Development experience: Demo2.html and other browser clients now work seamlessly
  • Production readiness: Both development and production entry points have identical behavior
  • Security maintained: Only OPTIONS requests bypass auth, all data requests still require valid JWTs

@hammadtq hammadtq merged commit 9ccc1b9 into dev Jul 25, 2025
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants