Update asgi_app.py

This commit is contained in:
saidsurucu
2025-07-08 22:46:58 +03:00
parent b86c18c842
commit 91895f6c1a
+67 -9
View File
@@ -12,8 +12,9 @@ Usage:
import os import os
import jwt import jwt
import time import time
import logging
from datetime import datetime, timedelta from datetime import datetime, timedelta
from fastapi import FastAPI, Request, HTTPException from fastapi import FastAPI, Request, HTTPException, Query
from fastapi.responses import JSONResponse, HTMLResponse from fastapi.responses import JSONResponse, HTMLResponse
from fastapi.exception_handlers import http_exception_handler from fastapi.exception_handlers import http_exception_handler
from starlette.middleware import Middleware from starlette.middleware import Middleware
@@ -34,6 +35,9 @@ CLERK_ISSUER = os.getenv("CLERK_ISSUER", "https://accounts.yargimcp.com")
BASE_URL = os.getenv("BASE_URL", "https://yargimcp.com") BASE_URL = os.getenv("BASE_URL", "https://yargimcp.com")
JWT_SECRET = os.getenv("JWT_SECRET_KEY", "your-secret-key-here") JWT_SECRET = os.getenv("JWT_SECRET_KEY", "your-secret-key-here")
# Setup logging
logger = logging.getLogger(__name__)
# Configure CORS middleware # Configure CORS middleware
cors_origins = os.getenv("ALLOWED_ORIGINS", "*").split(",") cors_origins = os.getenv("ALLOWED_ORIGINS", "*").split(",")
custom_middleware = [ custom_middleware = [
@@ -367,38 +371,65 @@ def validate_mcp_token(token: str) -> dict:
except jwt.InvalidTokenError: except jwt.InvalidTokenError:
raise HTTPException(status_code=401, detail="Invalid token") raise HTTPException(status_code=401, detail="Invalid token")
async def validate_clerk_session(request: Request) -> str: async def validate_clerk_session(request: Request, clerk_token: str = None) -> str:
"""Validate Clerk session from cookies and return user_id""" """Validate Clerk session from cookies or JWT token and return user_id"""
logger.info(f"Validating Clerk session - token provided: {bool(clerk_token)}")
try: try:
# Try to import Clerk SDK # Try to import Clerk SDK
from clerk_backend_api import Clerk from clerk_backend_api import Clerk
clerk = Clerk(bearer_auth=os.getenv("CLERK_SECRET_KEY"))
# Get Clerk session from cookies # Try JWT token first (from URL parameter)
if clerk_token:
logger.info("Validating Clerk JWT token from URL parameter")
try:
# Verify JWT token with Clerk
jwt_claims = clerk.jwt_templates.verify_token(clerk_token)
user_id = jwt_claims.get("sub")
if user_id:
logger.info(f"JWT token validation successful - user_id: {user_id}")
return user_id
else:
logger.error("JWT token validation failed - no user_id in claims")
except Exception as e:
logger.error(f"JWT token validation failed: {str(e)}")
# Fall through to cookie validation
# Fallback to cookie validation
logger.info("Attempting cookie-based session validation")
clerk_session = request.cookies.get("__session") clerk_session = request.cookies.get("__session")
if not clerk_session: if not clerk_session:
logger.error("No Clerk session cookie found")
raise HTTPException(status_code=401, detail="No Clerk session found") raise HTTPException(status_code=401, detail="No Clerk session found")
# Validate session with Clerk # Validate session with Clerk
clerk = Clerk(bearer_auth=os.getenv("CLERK_SECRET_KEY"))
session = clerk.sessions.verify_session(clerk_session) session = clerk.sessions.verify_session(clerk_session)
logger.info(f"Cookie session validation successful - user_id: {session.user_id}")
return session.user_id return session.user_id
except ImportError: except ImportError:
# Fallback for development without Clerk SDK # Fallback for development without Clerk SDK
logger.warning("Clerk SDK not available - using development fallback")
return "dev_user_123" return "dev_user_123"
except Exception as e: except Exception as e:
logger.error(f"Session validation failed: {str(e)}")
raise HTTPException(status_code=401, detail=f"Session validation failed: {str(e)}") raise HTTPException(status_code=401, detail=f"Session validation failed: {str(e)}")
# MCP OAuth Callback Endpoint # MCP OAuth Callback Endpoint
@app.get("/auth/callback") @app.get("/auth/callback")
async def mcp_oauth_callback(request: Request): async def mcp_oauth_callback(request: Request, clerk_token: str = Query(None)):
"""Handle OAuth callback for MCP token generation""" """Handle OAuth callback for MCP token generation"""
logger.info(f"MCP OAuth callback - clerk_token provided: {bool(clerk_token)}")
try: try:
# Validate Clerk session # Validate Clerk session with JWT token support
user_id = await validate_clerk_session(request) user_id = await validate_clerk_session(request, clerk_token)
logger.info(f"User authenticated successfully - user_id: {user_id}")
# Generate MCP token # Generate MCP token
mcp_token = generate_mcp_token(user_id) mcp_token = generate_mcp_token(user_id)
logger.info("MCP token generated successfully")
# Return success response # Return success response
return HTMLResponse(f""" return HTMLResponse(f"""
@@ -434,6 +465,7 @@ async def mcp_oauth_callback(request: Request):
""") """)
except HTTPException as e: except HTTPException as e:
logger.error(f"MCP OAuth callback failed: {e.detail}")
return HTMLResponse(f""" return HTMLResponse(f"""
<html> <html>
<head> <head>
@@ -441,16 +473,42 @@ async def mcp_oauth_callback(request: Request):
<style> <style>
body {{ font-family: Arial, sans-serif; text-align: center; padding: 50px; }} body {{ font-family: Arial, sans-serif; text-align: center; padding: 50px; }}
.error {{ color: #dc3545; }} .error {{ color: #dc3545; }}
.debug {{ background: #f8f9fa; padding: 10px; margin: 20px 0; border-radius: 5px; font-family: monospace; }}
</style> </style>
</head> </head>
<body> <body>
<h1 class="error">❌ MCP Connection Failed</h1> <h1 class="error">❌ MCP Connection Failed</h1>
<p>{e.detail}</p> <p>{e.detail}</p>
<div class="debug">
<strong>Debug Info:</strong><br>
Clerk Token: {'✅ Provided' if clerk_token else '❌ Missing'}<br>
Error: {e.detail}<br>
Status: {e.status_code}
</div>
<p>Please try again or contact support.</p> <p>Please try again or contact support.</p>
<a href="https://yargimcp.com/sign-in">Return to Sign In</a> <a href="https://yargimcp.com/sign-in">Return to Sign In</a>
</body> </body>
</html> </html>
""", status_code=e.status_code) """, status_code=e.status_code)
except Exception as e:
logger.error(f"Unexpected error in MCP OAuth callback: {str(e)}")
return HTMLResponse(f"""
<html>
<head>
<title>MCP Connection Error</title>
<style>
body {{ font-family: Arial, sans-serif; text-align: center; padding: 50px; }}
.error {{ color: #dc3545; }}
</style>
</head>
<body>
<h1 class="error">❌ Unexpected Error</h1>
<p>An unexpected error occurred during authentication.</p>
<p>Error: {str(e)}</p>
<a href="https://yargimcp.com/sign-in">Return to Sign In</a>
</body>
</html>
""", status_code=500)
# MCP Token Endpoint (for OAuth2 compatibility) # MCP Token Endpoint (for OAuth2 compatibility)
@app.post("/auth/token") @app.post("/auth/token")