-
Notifications
You must be signed in to change notification settings - Fork 41
Open
Description
Hello! I am currently facing an intermittent issue (happens like once a day for users) where the the token is either expired or invalid when we are sending it from our svelte frontend to our fastapi backend using getToken. The tokens seem to be valid because our sveltekit frontend isn't booting users out of their sessions, instead it just seems like authenticated requests to the fastapi backend fail sometimes (though rarely enough that it is hard to reproduce. I imagine it might have something to do with JWKS? I have attached source code and some screenshots. Thanks for building this api it has been a lifesaver!
Frontend svelte-clerk code:
const headers = new Headers();
headers.set('Authorization', `Bearer ${await ctx.session?.getToken()}`);
headers.set('Origin', 'new-originalis-webapp');
// Make request
const response = await fetch(`${baseApiUrl}/api/chat`, {
method: 'POST',
headers: headers,
body: formData
});Python backend code:
@router.post("/api/chat")
async def handle_chat(
request: Request,
user_id: str = Depends(get_current_user_id),
conversation_manager: ConversationManager = Depends(get_conversation_manager),
chat_service: ChatService = Depends(get_chat_service),
file_dal: FileDAL = Depends(get_file_dal),
):
"""Handle AI chat streaming with tool support and clarification system.
Supports ChatGPT-style temporary conversations:
- When thread_id is None/null: Creates new conversation thread automatically
- Returns real thread ID in 'x-conversation-thread-id' header for frontend to persist
- All messages are immediately stored in database (no truly "temporary" conversations)
- Frontend can treat conversations as temporary until user takes action to persist them
"""
async def get_current_user_id(request: Request) -> Optional[str]:
# For the time being we will only route to clerk if the origin is the new originalis webapp.
origin = request.headers.get("origin", "unknown")
logging.info(
f"Authentication routing decision - Origin: {origin}, Path: {request.url.path}"
)
if request.headers.get("origin") in CLERK_ALLOWED_ORIGINS:
logging.info("Routing to Clerk authentication")
try:
return await get_clerk_current_user_id(request)
except Exception as e:
logging.error(f"Clerk authentication failed: {str(e)}", exc_info=True)
raise
else:
logging.info("Routing to legacy Auth0 authentication")
try:
user = await get_current_user(request)
user_id = str(user.get("sub"))
logging.info(f"Legacy Auth0 authentication successful for user: {user_id}")
return user_id
except Exception as e:
logging.error(
f"Legacy Auth0 authentication failed: {str(e)}", exc_info=True
)
logging.error(
f"Request details - Origin: {origin}, Path: {request.url.path}, Method: {request.method}"
)
return None
async def get_clerk_current_user_id(request: Request) -> str:
"""
Dependency to get the current authenticated user from the bearer token generated by
Clerk on the frontend webapp.
@param request: The FastAPI request object with headers and session
@return: A dictionary containing the user information
Raises:
HTTPException: With 401 status code when authentication fails
"""
credentials_exception = HTTPException(
status_code=StatusCode.UNAUTHORIZED,
detail="Could not validate credentials",
headers={"WWW-Authenticate": "Bearer"},
)
# Log request details for debugging
auth_header = request.headers.get("Authorization", "")
origin = request.headers.get("origin", "unknown")
user_agent = request.headers.get("user-agent", "unknown")
logging.info(
f"Attempting Clerk authentication - Origin: {origin}, User-Agent: {user_agent[:100]}"
)
logging.debug(
f"Auth header present: {bool(auth_header)}, Length: {len(auth_header) if auth_header else 0}"
)
try:
request_state = authenticate_request(
request,
AuthenticateRequestOptions(
secret_key=clerk_settings.CLERK_API_SECRET_KEY,
authorized_parties=CLERK_ALLOWED_ORIGINS,
),
)
logging.debug(
f"Clerk authentication result - Signed in: {request_state.is_signed_in}, Message: {getattr(request_state, 'message', 'N/A')}"
)
if not request_state.is_signed_in:
logging.warning(
f"Clerk authentication failed - User not signed in. Message: {getattr(request_state, 'message', 'N/A')}"
)
logging.warning(
f"Request details - Origin: {origin}, Path: {request.url.path}, Method: {request.method}"
)
raise HTTPException(
status_code=status.HTTP_401_UNAUTHORIZED,
detail=request_state.message,
headers={"WWW-Authenticate": "Bearer"},
)
user_id: str | None = request_state.payload.get("sub")
if user_id is None:
logging.error(
f"Clerk authentication succeeded but no user ID found in payload. Payload keys: {list(request_state.payload.keys()) if hasattr(request_state, 'payload') else 'N/A'}"
)
logging.error(
f"Request details - Origin: {origin}, Path: {request.url.path}, Method: {request.method}"
)
raise credentials_exception
logging.info(f"Clerk authentication successful for user: {user_id}")
return user_id
except HTTPException:
# Re-raise HTTPExceptions as-is (these are intentional auth failures)
raise
except Exception as e:
logging.error(
f"Unexpected error during Clerk authentication: {str(e)}", exc_info=True
)
logging.error(
f"Request details - Origin: {origin}, Path: {request.url.path}, Method: {request.method}"
)
logging.error(f"Auth header present: {bool(auth_header)}")
raise eBug reports:

Reactions are currently unavailable
Metadata
Metadata
Assignees
Labels
No labels