{"record":{"id":"7cc30edfb6683273","repo":"unslothai/unsloth","slug":"invalid-token-payload","errorCode":null,"errorMessage":"Invalid token payload","messagePattern":"Invalid token payload","errorType":"http","errorClass":"HTTPException","httpStatus":401,"severity":"error","filePath":"studio/backend/auth/authentication.py","lineNumber":277,"sourceCode":"    a reset landing mid-request would bless what it just revoked.\n    \"\"\"\n    token = credentials.credentials\n\n    # --- API key path (sk-unsloth-...) ---\n    if token.startswith(API_KEY_PREFIX):\n        verified = validate_api_key_with_credential(token)\n        if verified is None:\n            raise HTTPException(\n                status_code = status.HTTP_401_UNAUTHORIZED,\n                detail = _invalid_api_key_detail(token),\n            )\n        username, secret = verified\n        return username, credential_generation(secret)\n\n    # --- JWT path ---\n    subject = _decode_subject_without_verification(token)\n    if subject is None:\n        raise HTTPException(\n            status_code = status.HTTP_401_UNAUTHORIZED,\n            detail = \"Invalid token payload\",\n        )\n\n    record = get_user_and_secret(subject)\n    if record is None:\n        raise HTTPException(\n            status_code = status.HTTP_401_UNAUTHORIZED,\n            detail = \"Invalid or expired token\",\n        )\n\n    _salt, _pwd_hash, jwt_secret, must_change_password = record\n    try:\n        payload = jwt.decode(token, jwt_secret, algorithms = [ALGORITHM])\n        if payload.get(\"sub\") != subject:\n            raise HTTPException(\n                status_code = status.HTTP_401_UNAUTHORIZED,\n                detail = \"Invalid token payload\",","sourceCodeStart":259,"sourceCodeEnd":295,"githubUrl":"https://github.com/unslothai/unsloth/blob/203007d19051dcd2ae33876786d117c99f6b0368/studio/backend/auth/authentication.py#L259-L295","documentation":"HTTP 401 raised when _decode_subject_without_verification cannot extract a subject from the bearer token: jwt.decode with signature/expiration verification disabled still failed to yield a usable 'sub' claim. That means the token is not a well-formed JWT (or lacks a sub), so it can be neither routed to the API-key path nor to the JWT verification path.","triggerScenarios":"Sending a malformed or truncated JWT string in the Authorization header; sending an opaque session string or random token where a JWT is expected; a JWT whose payload has no 'sub' claim; base64 corruption of the payload segment.","commonSituations":"Manually crafting auth headers; a proxy or client library mangling the header; using the wrong token type for the API (e.g. a CSRF token or opaque id); copy/paste truncating the token at a newline.","solutions":["Send a real, complete JWT previously issued by the login endpoint (three dot-separated base64url segments ending in a signature).","Check the token was not truncated or altered in transit (env var quoting, Docker secrets, CI masking).","If integrating programmatically, obtain the token from the login flow rather than hand-building one."],"exampleFix":"# before\nheaders = {\"Authorization\": \"Bearer not-a-jwt\"}\n\n# after\nresp = requests.post(f\"{base}/login\", json={...})\nheaders = {\"Authorization\": f\"Bearer {resp.json()['access_token']}\"}","handlingStrategy":"type-guard","validationCode":null,"typeGuard":"def looks_like_jwt(token: str) -> bool:\n    parts = token.split('.')\n    return len(parts) == 3 and all(parts)","tryCatchPattern":"try:\n    client.get('/api/x', headers=bearer(tok))\nexcept HTTPStatusError as e:\n    if e.response.status_code == 401 and 'Invalid token payload' in e.response.text:\n        tok = login()  # obtain a real JWT","preventionTips":["Always source tokens from the login endpoint; never hand-build auth headers.","Validate the three-segment JWT shape client-side before sending.","Check env/quoting for truncation when tokens move through CI or containers."],"tags":["authentication","jwt","http-401","studio"],"backgroundTag":null,"analyzedSha":"203007d19051dcd2ae33876786d117c99f6b0368","analyzedAt":"2026-08-15T02:48:39.846Z","schemaVersion":2},"datasetVersion":"2026-08-15T17:31:12.345Z"}