lcobucci/jwt · error · Lcobucci\JWT\Token\InvalidTokenStructure

The JWT string must have two dots

Error message

The JWT string must have two dots

What it means

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.

Solutions

  1. Verify you pass only the JWT itself, not the full 'Bearer xxx' header — strip the scheme prefix
  2. Count the dots before parsing: substr_count($jwt, '.') === 2
  3. If you received a 5-segment string, it is a JWE — this parser does not support encrypted tokens
  4. Catch InvalidTokenStructure around parse() and return a clear client error

Example fix

// before
$token = $parser->parse($request->getHeader('Authorization')[0]);
// after
$jwt = str_replace('Bearer ', '', $request->getHeader('Authorization')[0]);
if (substr_count($jwt, '.') !== 2) {
    throw new InvalidArgumentException('Not a compact JWT');
}
$token = $parser->parse($jwt);
Defensive patterns

Strategy: validation

Validate before calling

if (substr_count($jwt, '.') !== 2) { throw new InvalidArgumentException('Not a compact JWS (needs exactly two dots)'); }

Type guard

function isCompactJwt(string $s): bool { return substr_count($s, '.') === 2; }

Try / catch

try { $token = $parser->parse($jwt); } catch (Lcobucci\JWT\InvalidTokenStructure $e) { return error_401('Malformed token'); }

Prevention

When it happens

Trigger: 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.

Common situations: 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.

Understand the failure class

Background: "Invalid ... format", "must be in format X", "does not look like a ..." — invalid argument format errors across CLI tools and libraries — this error's family across 17 libraries.

Related errors


AI-assisted analysis of lcobucci/jwt@375813049c (2026-09-14). Data as JSON: /api/errors/e480a04e315124e9. Report an issue: GitHub.

Appendix: source

Thrown at src/Token/Parser.php:65

            $this->parseSignature($encodedSignature),
        );
    }

    /**
     * Splits the JWT string into an array
     *
     * @param non-empty-string $jwt
     *
     * @return string[]
     *
     * @throws InvalidTokenStructure When JWT doesn't have all parts.
     */
    private function splitJwt(string $jwt): array
    {
        $data = explode('.', $jwt);

        if (count($data) !== 3) {
            throw InvalidTokenStructure::missingOrNotEnoughSeparators();
        }

        return $data;
    }

    /**
     * Parses the header from a string
     *
     * @param non-empty-string $data
     *
     * @return array<non-empty-string, mixed>
     *
     * @throws UnsupportedHeaderFound When an invalid header is informed.
     * @throws InvalidTokenStructure  When parsed content isn't an array.
     */
    private function parseHeader(string $data): array
    {
        $header = $this->decoder->jsonDecode($this->decoder->base64UrlDecode($data));

View on GitHub (pinned to 375813049c)