{"record":{"id":"48823658d967e5cd","repo":"tymondesigns/jwt-auth","slug":"malformed-token","errorCode":null,"errorMessage":"Malformed token","messagePattern":"Malformed token","errorType":"exception","errorClass":"Tymon\\JWTAuth\\Exceptions\\TokenInvalidException","httpStatus":null,"severity":"error","filePath":"src/Validators/TokenValidator.php","lineNumber":46,"sourceCode":"\n    /**\n     * @param  string  $token\n     * @return string\n     *\n     * @throws \\Tymon\\JWTAuth\\Exceptions\\TokenInvalidException\n     */\n    protected function validateStructure($token)\n    {\n        $parts = explode('.', $token);\n\n        if (count($parts) !== 3) {\n            throw new TokenInvalidException('Wrong number of segments');\n        }\n\n        $parts = array_filter(array_map('trim', $parts));\n\n        if (count($parts) !== 3 || implode('.', $parts) !== $token) {\n            throw new TokenInvalidException('Malformed token');\n        }\n\n        return $token;\n    }\n}\n","sourceCodeStart":28,"sourceCodeEnd":52,"githubUrl":"https://github.com/tymondesigns/jwt-auth/blob/6c70930a92710d97e8e52b182fca2176097f33be/src/Validators/TokenValidator.php#L28-L52","documentation":"Thrown by TokenValidator::validateStructure() when the string has three dot-separated segments but they are not clean non-empty base64url bodies: after trim() and removal of empty segments the count changes, or rejoining the trimmed parts no longer reproduces the original. Concretely, at least one segment is empty (e.g. 'header..signature') or contains whitespace/line breaks inside it.","triggerScenarios":"Passing a token where the payload or signature segment is empty, or where any segment carries leading/trailing spaces, tabs, or embedded newlines - e.g. a token wrapped across lines by an email client, a header value folded by a proxy, or a copy-paste that introduced a space. Caught in TokenValidator::check, reached from new Token($value) inside JWTAuth::parseToken()->authenticate().","commonSituations":"Token truncated or wrapped to multiple lines before being sent; whitespace sneaking in through copy-paste or template interpolation; a client sending a two-part unsigned JWT ('header.payload.') which has an empty signature segment; middleware or proxies re-encoding the Authorization header; a token stored in a database TEXT column with a trailing newline.","solutions":["Log the received token wrapped in delimiters (e.g. \"[$token]\") to reveal invisible whitespace or embedded newlines","Strip surrounding whitespace on the server before parsing if the transport adds it: $token = preg_replace('/\\s+/', '', $token) - but fix the producer if whitespace appears inside the token","Regenerate/re-login to obtain a clean token if the stored one was wrapped or truncated","If you control the client, ensure the token is transmitted as a single line with no formatting applied (no word-wrap, no pretty-printing in storage)"],"exampleFix":"// before - token wrapped across lines in transit\n\"eyJhbGciOi...\\neyJzdWIi...\\n.E-mSig\"  // TokenInvalidException: Malformed token\n\n// after - normalize at the boundary, then parse\n$token = preg_replace('/\\s+/', '', $request->bearerToken());\n$user = JWTAuth::parseToken()->authenticate();","handlingStrategy":"type-guard","validationCode":"// Same strict shape check also rejects empty segments and embedded whitespace\nfunction looksLikeJwt(?string $token): bool\n{\n    return is_string($token)\n        && preg_match('/^[A-Za-z0-9_-]+\\.[A-Za-z0-9_-]+\\.[A-Za-z0-9_-]+$/', $token) === 1;\n}\n\n// optionally normalize transport noise first\n$token = preg_replace('/\\s+/', '', (string) $request->bearerToken());","typeGuard":"function looksLikeJwt(?string $token): bool\n{\n    return is_string($token)\n        && preg_match('/^[A-Za-z0-9_-]+\\.[A-Za-z0-9_-]+\\.[A-Za-z0-9_-]+$/', $token) === 1;\n}","tryCatchPattern":"use Tymon\\JWTAuth\\Exceptions\\TokenInvalidException;\n\ntry {\n    $user = auth('api')->parseToken()->authenticate();\n} catch (TokenInvalidException $e) {\n    // 'Malformed token' = structurally broken input; 401 and let the client re-authenticate\n    return response()->json(['error' => 'token_malformed'], 401);\n}","preventionTips":["Store and transmit JWTs as a single line - never wrap, pretty-print, or HTML-encode them","When logging tokens, wrap in delimiters (\"[$token]\") so invisible whitespace is visible in logs","Strip whitespace at the API boundary with preg_replace('/\\\\s+/', '', $token) if intermediaries fold headers","Treat a malformed-token spike as a transport regression - check proxies, copy-paste flows, and storage columns for truncation"],"tags":["jwt","php","laravel","token-format","whitespace","input-validation"],"backgroundTag":"jwt-malformed-token","analyzedSha":"6c70930a92710d97e8e52b182fca2176097f33be","analyzedAt":"2026-08-21T02:16:37.040Z","schemaVersion":2},"datasetVersion":"2026-08-21T03:17:12.404Z"}