Skip to content

create_session_token expires_in_seconds arg resulting in 400: request_body_invalid #85

@cosmic-ascendant

Description

@cosmic-ascendant

Version: clerk-backend-api 1.7.0
Possible related issue: #67
Summary: Passing in expires_in_seconds (as int or float) into clerk_client.create_session_token results in 400
Application: Testing backend auth

ERROR - Failed to create session token using SDK: API error occurred: Status 400                     
{"errors":[{"message":"Request body invalid","long_message":"The request body is invalid. Please consult the API documentation for more information."
,"code":"request_body_invalid"}],"clerk_trace_id":"2efb09d4de0199f552e1616b597cf0eb"}  

Here is code basis to reproduce, which includes a working manual request method and the non-working sdk method:

"""Utility for creating Clerk session tokens"""

import logging
from typing import Optional

import httpx
from clerk_backend_api import Clerk

logger = logging.getLogger(__name__)
formatter = logging.Formatter("%(asctime)s - %(levelname)s - %(message)s")
handler = logging.StreamHandler()
handler.setFormatter(formatter)
logger.addHandler(handler)


def _create_session_token_sdk(clerk_client: Clerk, session_id: str) -> Optional[str]:
    """Create a session token using the Clerk SDK (currently not working)"""
    try:
        token_response = clerk_client.sessions.create_session_token(
            session_id=session_id,
            expires_in_seconds=3600,
        )
        return token_response.jwt if token_response else None
    except Exception as e:
        logger.error(f"Failed to create session token using SDK: {str(e)}")
        return None


def _create_session_token_manual(clerk_client: Clerk, session_id: str) -> Optional[str]:
    """Create a session token using direct HTTP request"""
    try:
        url = f"https://api.clerk.com/v1/sessions/{session_id}/tokens"
        headers = {
            "Authorization": f"Bearer {clerk_client.sdk_configuration.security.bearer_auth}",
            "Content-Type": "application/json",
        }
        payload = {"expires_in_seconds": 3600}

        response = httpx.post(url, json=payload, headers=headers)

        if response.status_code == 200:
            return response.json()["jwt"]
        else:
            logger.error(f"Failed to create session token: {response.status_code}")
            logger.error(f"Response: {response.text}")
            return None
    except Exception as e:
        logger.error(f"Failed to create session token manually: {str(e)}")
        return None


def create_session_token(clerk_client: Clerk, clerk_user_id: str) -> Optional[str]:
    """Create a session token for a Clerk user"""
    try:
        # First create a session for the user
        logger.info(f"Creating session for user {clerk_user_id}")
        session = clerk_client.sessions.create_session(
            request={
                "user_id": clerk_user_id,
            }
        )

        if not session:
            logger.error(f"Failed to create session for user {clerk_user_id}")
            return None

        logger.info(f"Created session {session.id}, creating token...")

        # Using manual approach for now as SDK method is not working
        jwt = _create_session_token_manual(clerk_client, session.id)
        # jwt = _create_session_token_sdk(clerk_client, session.id)
        logger.info(f"Created session token for session {session.id}")
        return jwt

    except Exception as e:
        logger.error(f"Failed to create session: {str(e)}")
        return None

Activity

owentran

owentran commented on Feb 1, 2025

@owentran

I see the same issue with clerk-backend-api==1.7.2. I have to comment out expires_in_seconds to avoid the 400 invalid body error.

hsteidel

hsteidel commented on Feb 25, 2025

@hsteidel

I think I found the problem.

The issue is that the body model is typed to a float but the Service Side API wants an int

class CreateSessionTokenFromTemplateRequestBody(BaseModel):
    expires_in_seconds: OptionalNullable[float] = UNSET

Using the debugger and overriding the value to an int BEFORE the SDK builds and serialized the request works.

Image

Using the API page and trying out the same call confirms my suspicion that it wants an int

https://clerk.com/docs/reference/backend-api/tag/Sessions#operation/CreateSessionTokenFromTemplate

Image

alexmavr

alexmavr commented on Jul 17, 2025

@alexmavr

+1 on this issue

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

      Participants

      @alexmavr@owentran@hsteidel@cosmic-ascendant

      Issue actions

        `create_session_token` `expires_in_seconds` arg resulting in 400: `request_body_invalid` · Issue #85 · clerk/clerk-sdk-python