{"record":{"id":"21f49d757ca1670b","repo":"unslothai/unsloth","slug":"chatgpt-returned-an-invalid-access-token","errorCode":null,"errorMessage":"ChatGPT returned an invalid access token.","messagePattern":"ChatGPT returned an invalid access token\\.","errorType":"exception","errorClass":"CodexAuthError","httpStatus":400,"severity":"error","filePath":"studio/backend/core/inference/openai_codex_auth.py","lineNumber":193,"sourceCode":"        bundle[\"reauthorization_required\"] = True\n        save_oauth_bundle(provider_id, bundle)\n\n\ndef _b64url(data: bytes) -> str:\n    return base64.urlsafe_b64encode(data).decode(\"ascii\").rstrip(\"=\")\n\n\ndef create_pkce() -> tuple[str, str]:\n    verifier = _b64url(secrets.token_bytes(48))\n    challenge = _b64url(hashlib.sha256(verifier.encode(\"ascii\")).digest())\n    return verifier, challenge\n\n\ndef extract_chatgpt_account_id(access_token: str) -> str:\n    \"\"\"Decode only the bounded JWT payload needed as an upstream routing hint.\"\"\"\n    parts = access_token.split(\".\")\n    if len(parts) < 2 or len(parts[1]) > 16_384:\n        raise CodexAuthError(\"ChatGPT returned an invalid access token.\")\n    try:\n        raw = base64.urlsafe_b64decode(parts[1] + \"=\" * (-len(parts[1]) % 4))\n        payload = json.loads(raw)\n    except Exception as exc:\n        raise CodexAuthError(\"ChatGPT returned an invalid access token.\") from exc\n    account_id = payload.get(\"https://api.openai.com/auth\", {}).get(\"chatgpt_account_id\")\n    if not isinstance(account_id, str) or not account_id or len(account_id) > 512:\n        account_id = payload.get(\"https://api.openai.com/auth.chatgpt_account_id\")\n    if not isinstance(account_id, str) or not account_id or len(account_id) > 512:\n        raise CodexAuthError(\"The ChatGPT account identifier was missing.\")\n    return account_id\n\n\ndef _validate_token_payload(body: Any, previous_refresh_token: str = \"\") -> dict[str, Any]:\n    if not isinstance(body, dict):\n        raise CodexAuthError(\"ChatGPT returned an invalid token response.\")\n    access_token = body.get(\"access_token\")\n    refresh_token = body.get(\"refresh_token\") or previous_refresh_token","sourceCodeStart":175,"sourceCodeEnd":211,"githubUrl":"https://github.com/unslothai/unsloth/blob/203007d19051dcd2ae33876786d117c99f6b0368/studio/backend/core/inference/openai_codex_auth.py#L175-L211","documentation":"CodexAuthError from extract_chatgpt_account_id when the access token cannot be treated as a JWT: it must split into at least 2 dot-separated parts with a payload segment no larger than 16,384 chars (a deliberate bound before base64-decoding an untrusted string). Failing the split/size check, or the base64/JSON decode inside the try, both raise 'invalid access token' — the token is malformed, truncated, or not a JWT.","triggerScenarios":"Passing an access token with fewer than 2 dot-separated segments (e.g. an opaque token or truncated string), a payload segment over 16KB, or a payload that is not valid base64url/JSON. Raised during token validation after any successful token exchange.","commonSituations":"Upstream auth changes where access_token stops being a JWT; string truncation when copying/storing the token; a proxy or logging layer mangling the header; non-ChatGPT OpenAI tokens with a different shape.","solutions":["Inspect the token string: it should look like 'xxxxx.yyyyy.zzzzz' with a decodable middle segment — if not, re-run the OAuth flow to obtain a fresh token.","Check that nothing in your storage/transport layer truncates or re-encodes the token (column length limits, URL encoding).","If upstream genuinely changed the token format, update extract_chatgpt_account_id to match the new claim location/format."],"exampleFix":null,"handlingStrategy":"validation","validationCode":"parts = access_token.split('.')\nif len(parts) < 2 or len(parts[1]) > 16_384:\n    raise ValueError('not a plausible JWT; re-authenticate')","typeGuard":"def looks_like_jwt(token: str) -> bool:\n    parts = token.split('.')\n    return len(parts) >= 2 and 0 < len(parts[1]) <= 16_384","tryCatchPattern":"try:\n    account_id = extract_chatgpt_account_id(access_token)\nexcept CodexAuthError as e:\n    if 'invalid access token' in str(e):\n        trigger_full_reauth(provider_id)  # token unusable; get a new one\n    else:\n        raise","preventionTips":["Check the token shape (dot-separated, bounded payload) before calling extract.","Store tokens verbatim; never truncate or re-encode them.","Treat repeated 'invalid access token' as an upstream format change — verify against a known-good token."],"tags":["oauth","jwt","token-validation","codex"],"backgroundTag":null,"analyzedSha":"203007d19051dcd2ae33876786d117c99f6b0368","analyzedAt":"2026-08-15T02:48:39.846Z","schemaVersion":2},"datasetVersion":"2026-08-15T22:17:37.221Z"}