dgraph-io/dgraph · error
unable to parse jwt token
Error message
unable to parse jwt token
What it means
Any failure from jwt.Parse (bad signature, malformed token, missing key, expired, etc.) is wrapped with errors.Wrapf(err, "unable to parse jwt token") and returned. This wrapper is the outermost message; the underlying cause (available via errors.Unwrap/%v of err) explains the actual problem. Parse fails validation, so no claims are returned.
Source
Thrown at x/jwt_helper.go:45
return k
}
func ParseJWT(jwtStr string) (jwt.MapClaims, error) {
token, err := jwt.Parse(jwtStr, func(token *jwt.Token) (interface{}, error) {
if WorkerConfig.AclJwtAlg == nil {
return nil, errors.Errorf("ACL is disabled")
}
if token.Method.Alg() != WorkerConfig.AclJwtAlg.Alg() {
return nil, errors.Errorf("unexpected signing method in token: %v", token.Header["alg"])
}
return MaybeKeyToBytes(WorkerConfig.AclPublicKey), nil
})
if err != nil {
// This is for backward compatibility in clients
if errors.Is(err, jwt.ErrTokenExpired) {
err = errors.Wrap(errTokenExpired, jwt.ErrTokenInvalidClaims.Error())
}
return nil, errors.Wrapf(err, "unable to parse jwt token")
}
claims, ok := token.Claims.(jwt.MapClaims)
if !ok || !token.Valid {
return nil, errors.Errorf("claims in jwt token is not map claims")
}
return claims, nil
}
func ExtractUserName(jwtToken string) (string, error) {
claims, err := ParseJWT(jwtToken)
if err != nil {
return "", err
}
userId, ok := claims["userid"].(string)
if !ok {
return "", errors.Errorf("userid in claims is not a string:%v", userId)
}View on GitHub (pinned to 759e242be6)
Solutions
- Inspect the wrapped cause: print errors.Unwrap(err) or the full chain to see whether it is signature, alg, expiry, or key loading.
- Verify WorkerConfig.AclPublicKey matches the private key that signed the token.
- Confirm the raw JWT string is complete and unmodified (no truncation, quotes, or newlines) before ParseJWT.
- Re-issue/refresh the token if the cause is expiry or wrong signing method.
Example fix
// before: opaque handling
if err != nil { return err }
// after: surface the cause
if err != nil {
return fmt.Errorf("jwt auth failed: %w", err) // shows underlying reason
} Defensive patterns
Strategy: try-catch
Try / catch
claims, err := x.ParseJWT(jwtToken)
if err != nil {
// unwrap to classify the cause
switch {
case errors.Is(err, jwt.ErrTokenExpired):
// refresh token and retry
case strings.Contains(err.Error(), "unexpected signing method"):
// re-issue with correct alg
case strings.Contains(err.Error(), "ACL is disabled"):
// fix server config
default:
// log full error chain: fmt.Printf("%+v", err)
}
return err
} Prevention
- Log wrapped errors with %+v (pkg/errors stack trace) to see the root cause.
- Validate the key/alg config before serving JWT-authenticated traffic.
- Keep tokens intact in transit (no trimming/quoting) — transport them in a standard Authorization header.
- Test auth flows after key rotations.
When it happens
Trigger: jwt.Parse returns any error during key-function callback (ACL disabled, wrong alg), signature verification failure, malformed token text, invalid claims, or expired token — via ParseJWT or its callers validateToken/ExtractUserName/ExtractNamespaceFromJwt.
Common situations: Wrong ACL public key configured so signatures never verify; truncated or whitespace-mangled token strings; tokens from a different cluster; the expired-token case above.
Understand the failure class
- Parsing and encoding errors: unexpected token, malformed input — why parsers reject input and how to find the real culprit.
Related errors
- expecting either JWKUrl or JWKUrls, both were given
- expecting either JWKUrl/JWKUrls or (VerificationKey, Algo),
- required field missing in Dgraph.Authorization:%s
- invalid Bearer-formatted header value for JWT (%s)
- audience value was expected but not provided
AI-assisted analysis of dgraph-io/dgraph@759e242be6 (2026-09-01).
Data as JSON: /api/errors/be28d003fd26d2a7.
Report an issue: GitHub.