Error message
token is malformed: token contains an invalid number of segments
Also printed as
- token is malformed: could not base64 decode header: illegal base64 data at input byte 6
- token contains an invalid number of segments
v5 prefixes "token is malformed: ". v4 prints the inner text only, e.g. "token contains an invalid number of segments". The byte offset in "illegal base64 data at input byte N" points at the first bad character.
golang-jwt/jwt (Go) — jwt.ErrTokenMalformed
What it means
golang-jwt could not even read the token's structure. "invalid number of segments" means the string does not have exactly two dots; "could not base64 decode header" means the first segment is not base64url — classically because the `Bearer ` prefix is still attached (byte 6 is the space). In v5 these are wrapped in `jwt.ErrTokenMalformed`; no key was looked up.
Why it happens
The Authorization header was parsed whole
common`r.Header.Get("Authorization")` returns `Bearer eyJ…`. Passed directly to `jwt.Parse`, the space makes the header segment invalid base64.
The value is not a JWT
commonOpaque OAuth access tokens, session IDs, API keys or an empty header reach the parser. Only strings with three base64url segments are JWS tokens.
An encrypted token (JWE) with five segments
occasionalSome identity providers encrypt tokens. golang-jwt handles only signed tokens; decrypt the JWE first (for example with go-jose) and parse the nested JWS.
The token was truncated
occasionalA database column, a cookie size limit (4 KB) or a log line cut the token, removing the last segment or dot.
How to fix it
- 1.
Use the request extractor
`github.com/golang-jwt/jwt/v5/request` strips the `Bearer` scheme case-insensitively and returns `request.ErrNoTokenInRequest` when there is no token at all.
go import "github.com/golang-jwt/jwt/v5/request" token, err := request.ParseFromRequest(r, request.OAuth2Extractor, keyfunc, request.WithParser(jwt.NewParser(jwt.WithValidMethods([]string{"ES256"})))) if err != nil { http.Error(w, "unauthorized", http.StatusUnauthorized) return } - 2.
Validate the shape before parsing
Counting dots separates JWS (2), JWE (4) and garbage. Answer 401 for anything that is not a token you can process.
go raw := strings.TrimSpace(strings.TrimPrefix(r.Header.Get("Authorization"), "Bearer ")) switch strings.Count(raw, ".") { case 2: // JWS: parse it case 4: // JWE: decrypt first (go-jose), golang-jwt does not handle encrypted tokens default: http.Error(w, "unauthorized", http.StatusUnauthorized) return }