{"record":{"id":"e480a04e315124e9","repo":"lcobucci/jwt","slug":"the-jwt-string-must-have-two-dots","errorCode":null,"errorMessage":"The JWT string must have two dots","messagePattern":"The JWT string must have two dots","errorType":"exception","errorClass":"Lcobucci\\JWT\\Token\\InvalidTokenStructure","httpStatus":null,"severity":"error","filePath":"src/Token/Parser.php","lineNumber":65,"sourceCode":"            $this->parseSignature($encodedSignature),\n        );\n    }\n\n    /**\n     * Splits the JWT string into an array\n     *\n     * @param non-empty-string $jwt\n     *\n     * @return string[]\n     *\n     * @throws InvalidTokenStructure When JWT doesn't have all parts.\n     */\n    private function splitJwt(string $jwt): array\n    {\n        $data = explode('.', $jwt);\n\n        if (count($data) !== 3) {\n            throw InvalidTokenStructure::missingOrNotEnoughSeparators();\n        }\n\n        return $data;\n    }\n\n    /**\n     * Parses the header from a string\n     *\n     * @param non-empty-string $data\n     *\n     * @return array<non-empty-string, mixed>\n     *\n     * @throws UnsupportedHeaderFound When an invalid header is informed.\n     * @throws InvalidTokenStructure  When parsed content isn't an array.\n     */\n    private function parseHeader(string $data): array\n    {\n        $header = $this->decoder->jsonDecode($this->decoder->base64UrlDecode($data));","sourceCodeStart":47,"sourceCodeEnd":83,"githubUrl":"https://github.com/lcobucci/jwt/blob/375813049c24c7111bda8b6884c57b071ceb2fe7/src/Token/Parser.php#L47-L83","documentation":"A JWT must contain exactly three dot-separated parts. Parser::splitJwt() explodes the string on '.' and throws InvalidTokenStructure::missingOrNotEnoughSeparators() when the resulting array does not have exactly 3 elements, i.e. the string must contain precisely two dots.","triggerScenarios":"Passing a string with fewer or more than two dots: 'header.claims' (unsigned), 'header.claims.sig.extra' (JWE or nested token), a whole Authorization header ('Bearer eyJ...' contains no dot issue but a JWE has 5 dots), or passing a non-JWT string.","commonSituations":"Accidentally passing an access token in JWE format; passing the raw Authorization header value including 'Bearer '; concatenating token + extra data; passing an opaque session token instead of a JWT.","solutions":["Verify you pass only the JWT itself, not the full 'Bearer xxx' header — strip the scheme prefix","Count the dots before parsing: substr_count($jwt, '.') === 2","If you received a 5-segment string, it is a JWE — this parser does not support encrypted tokens","Catch InvalidTokenStructure around parse() and return a clear client error"],"exampleFix":"// before\n$token = $parser->parse($request->getHeader('Authorization')[0]);\n// after\n$jwt = str_replace('Bearer ', '', $request->getHeader('Authorization')[0]);\nif (substr_count($jwt, '.') !== 2) {\n    throw new InvalidArgumentException('Not a compact JWT');\n}\n$token = $parser->parse($jwt);","handlingStrategy":"validation","validationCode":"if (substr_count($jwt, '.') !== 2) { throw new InvalidArgumentException('Not a compact JWS (needs exactly two dots)'); }","typeGuard":"function isCompactJwt(string $s): bool { return substr_count($s, '.') === 2; }","tryCatchPattern":"try { $token = $parser->parse($jwt); } catch (Lcobucci\\JWT\\InvalidTokenStructure $e) { return error_401('Malformed token'); }","preventionTips":["Strip the 'Bearer ' scheme before parsing","Recognize 5-dot strings as JWE and route them to a JWE-capable library","Validate token shape centrally before any parser call"],"tags":["jwt","parser","malformed-token","php"],"backgroundTag":"invalid-argument-format","analyzedSha":"375813049c24c7111bda8b6884c57b071ceb2fe7","analyzedAt":"2026-09-14T11:12:28.004Z","contentChangedAt":"2026-09-14T11:12:28.004Z","schemaVersion":2},"datasetVersion":"2026-09-16T09:17:16.951Z"}