{"record":{"id":"944ed0cb2adbc8c4","repo":"PrefectHQ/fastmcp","slug":"invalid-jwt-format-expected-3-parts","errorCode":null,"errorMessage":"Invalid JWT format (expected 3 parts)","messagePattern":"Invalid JWT format \\(expected 3 parts\\)","errorType":"exception","errorClass":"ValueError","httpStatus":null,"severity":"error","filePath":"fastmcp_slim/fastmcp/utilities/auth.py","lineNumber":25,"sourceCode":"from typing import Any\n\n\ndef _decode_jwt_part(token: str, part_index: int) -> dict[str, Any]:\n    \"\"\"Decode a JWT part (header or payload) without signature verification.\n\n    Args:\n        token: JWT token string (header.payload.signature)\n        part_index: 0 for header, 1 for payload\n\n    Returns:\n        Decoded part as a dictionary\n\n    Raises:\n        ValueError: If token is not a valid JWT format\n    \"\"\"\n    parts = token.split(\".\")\n    if len(parts) != 3:\n        raise ValueError(\"Invalid JWT format (expected 3 parts)\")\n\n    part_b64 = parts[part_index]\n    part_b64 += \"=\" * (-len(part_b64) % 4)  # Add padding\n    return json.loads(base64.urlsafe_b64decode(part_b64))\n\n\ndef decode_jwt_header(token: str) -> dict[str, Any]:\n    \"\"\"Decode JWT header without signature verification.\n\n    Useful for extracting the key ID (kid) for JWKS lookup.\n\n    Args:\n        token: JWT token string (header.payload.signature)\n\n    Returns:\n        Decoded header as a dictionary\n\n    Raises:","sourceCodeStart":7,"sourceCodeEnd":43,"githubUrl":"https://github.com/PrefectHQ/fastmcp/blob/1f021142978e0861cd910c8df4e8074bc7cf3978/fastmcp_slim/fastmcp/utilities/auth.py#L7-L43","documentation":"decode_jwt_header/decode_jwt_payload expect a JWT with exactly three dot-separated parts (header.payload.signature). Tokens that are opaque strings, access tokens in other formats, or truncated JWTs fail this check with a ValueError.","triggerScenarios":"Passing a non-JWT token (e.g. an OAuth opaque access token or API key) to decode_jwt_header or decode_jwt_payload, or a JWT missing its signature part.","commonSituations":"Misconfiguring auth so an opaque provider token is treated as a JWT; copying a token partially; using ID-token decoding helpers on access tokens from providers like Auth0 or Google that are not JWTs.","solutions":["Verify the token is a JWT (two dots, base64url segments) before decoding","Decode the ID token instead of the access token when using OAuth providers","Check provider settings to ensure JWTs are being issued (RS256/HS256 signed tokens)"],"exampleFix":"// before\nheader = decode_jwt_header(access_token)\n\n// after\nif access_token.count(\".\") == 3 - 1:\n    header = decode_jwt_header(access_token)","handlingStrategy":"validation","validationCode":"def looks_like_jwt(token: str) -> bool:\n    parts = token.split(\".\")\n    return len(parts) == 3 and all(parts)","typeGuard":"def is_jwt(token: object) -> bool:\n    return isinstance(token, str) and token.count(\".\") == 2","tryCatchPattern":"try:\n    claims = decode_jwt_payload(token)\nexcept ValueError as e:\n    if \"Invalid JWT format\" in str(e):\n        # token is opaque or truncated; fetch/verify the real JWT\n        ...\n    else:\n        raise","preventionTips":["Confirm the provider issues JWT access tokens before decoding","Decode ID tokens, not opaque access tokens","Validate token shape with token.count(\".\") == 2 first"],"tags":["python","jwt","auth","base64"],"backgroundTag":"invalid-jwt-format","analyzedSha":"1f021142978e0861cd910c8df4e8074bc7cf3978","analyzedAt":"2026-08-29T14:31:16.082Z","schemaVersion":2},"datasetVersion":"2026-08-29T17:17:51.833Z"}