Error message
Wrong number of segments
Also printed as
- UnexpectedValueException: Wrong number of segments
- Unexpected control character found
Prefixed with the class name when printed: "UnexpectedValueException: Wrong number of segments". The `Bearer` prefix case produces "Unexpected control character found" (a `DomainException`) instead.
firebase/php-jwt (PHP) — UnexpectedValueException from JWT::decode
What it means
`JWT::decode` split the input on dots and did not get exactly three parts, so it is not a compact JWS and nothing else was checked. In PHP applications the most common source is an empty string: the web server did not pass the `Authorization` header to PHP, and the code fell back to `''`. A token that still carries the `Bearer ` prefix has three segments but fails one step later, typically with "Unexpected control character found" from the JSON decoder.
Why it happens
The Authorization header never reached PHP
commonApache with PHP-FPM or CGI strips `Authorization` unless configured to pass it, and some hosting panels do the same. The client sends the header; `$_SERVER['HTTP_AUTHORIZATION']` is unset.
The value is not a JWT
commonA session ID, an opaque OAuth access token, an API key, or `"null"` sent by a JavaScript client that had no token yet.
Scheme or quotes left in the string
occasionalPassing the whole header value, or a JSON-encoded token with quotes, breaks parsing of the first segment.
How to fix it
- 1.
Read the header robustly and validate the shape
Look in the places different server setups put the header, accept only `Bearer <three base64url segments>`, and answer 401 otherwise.
php function bearerToken(): ?string { $header = $_SERVER['HTTP_AUTHORIZATION'] ?? $_SERVER['REDIRECT_HTTP_AUTHORIZATION'] // Apache + mod_rewrite ?? (function_exists('apache_request_headers') ? (apache_request_headers()['Authorization'] ?? '') : ''); if (!preg_match('/^Bearer\s+([A-Za-z0-9_-]+\.[A-Za-z0-9_-]+\.[A-Za-z0-9_-]*)$/', $header, $m)) { return null; } return $m[1]; } - 2.
Make Apache pass the header
`CGIPassAuth On` (Apache 2.4.13+) or a rewrite rule exposes `Authorization` to PHP.
text # Apache with PHP-FPM / CGI: pass the Authorization header through CGIPassAuth On # or, with mod_rewrite: RewriteRule .* - [E=HTTP_AUTHORIZATION:%{HTTP:Authorization}]