{"record":{"id":"a961958ce81355ae","repo":"HumanSignal/label-studio","slug":"invalid-label-studio-token","errorCode":null,"errorMessage":"Invalid Label Studio token","messagePattern":"Invalid Label Studio token","errorType":"exception","errorClass":"TokenError","httpStatus":null,"severity":"error","filePath":"label_studio/jwt_auth/models.py","lineNumber":125,"sourceCode":"        Raises:\n            rest_framework_simplejwt.exceptions.TokenError: If the token is already blacklisted.\n        \"\"\"\n        self.check_blacklist()\n        return super().blacklist()\n\n\nclass TruncatedLSAPIToken(LSAPIToken):\n    \"\"\"Handles JWT tokens that contain only header and payload (no signature).\n    Used when frontend has access to truncated refresh tokens only.\"\"\"\n\n    def __init__(self, token, *args, **kwargs):\n        \"\"\"Initialize a truncated token, ensuring it has exactly 2 parts before adding a dummy signature.\"\"\"\n        # Ensure we have exactly 2 parts (header and payload)\n        parts = token.split('.')\n        if len(parts) > 2:\n            token = '.'.join(parts[:2])\n        elif len(parts) < 2:\n            raise TokenError('Invalid Label Studio token')\n\n        # Add dummy signature with exactly 43 'x' characters to match expected JWT signature length\n        token = token + '.' + ('x' * 43)\n        super().__init__(token, verify=False, *args, **kwargs)\n","sourceCodeStart":107,"sourceCodeEnd":130,"githubUrl":"https://github.com/HumanSignal/label-studio/blob/0b49e9b53917880baf1dd85d574fe5541a9aafb2/label_studio/jwt_auth/models.py#L107-L130","documentation":"Raised by TruncatedToken.__init__ when the supplied string does not contain at least two dot-separated parts (header and payload) of a JWT. The class truncates a token to its first two parts before adding a dummy signature, and rejects anything that cannot even be shaped like a JWT.","triggerScenarios":"Passing a malformed string (no '.', or only one segment) into the truncated-token wrapper used during API token authentication/inspection, e.g. a plain API key or corrupted token value.","commonSituations":"User pasted a non-JWT legacy token where a JWT token was expected; token truncated/corrupted in storage; whitespace or copy-paste errors dropped part of the token; passing an empty string.","solutions":["Verify the token string has the form '<header>.<payload>' (JWT format) before calling","Re-issue the token from Label Studio (new JWT API token)","Strip surrounding whitespace/quotes that may corrupt the token","Use the correct token type: legacy API keys are not JWTs and need the legacy auth path"],"exampleFix":"// before\nTruncatedToken(user_api_key)  # plain string, no dots\n// after\nif user_token.count('.') >= 1:\n    TruncatedToken(user_token)\nelse:\n    reissue_new_jwt_token()","handlingStrategy":"type-guard","validationCode":"def is_jwt_shaped(token: str) -> bool:\n    parts = token.strip().split('.')\n    return len(parts) >= 2 and all(parts)","typeGuard":"def is_valid_ls_token(token: str) -> bool:\n    return isinstance(token, str) and len(token.strip().split('.')) >= 2","tryCatchPattern":"try:\n    tok = TruncatedToken(raw_token)\nexcept TokenError:\n    raise ValueError('Token is not JWT-shaped; re-issue from Label Studio')","preventionTips":["Validate token format (two+ dot-separated parts) before storing/using","Never paste legacy plain API keys where JWT tokens are expected","Trim whitespace/quotes when copying tokens"],"tags":["jwt","token","validation","auth"],"backgroundTag":"malformed-jwt-token","analyzedSha":"0b49e9b53917880baf1dd85d574fe5541a9aafb2","analyzedAt":"2026-08-29T00:39:52.578Z","schemaVersion":2},"datasetVersion":"2026-08-29T02:17:18.158Z"}