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

  1. Inspect the wrapped cause: print errors.Unwrap(err) or the full chain to see whether it is signature, alg, expiry, or key loading.
  2. Verify WorkerConfig.AclPublicKey matches the private key that signed the token.
  3. Confirm the raw JWT string is complete and unmodified (no truncation, quotes, or newlines) before ParseJWT.
  4. 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

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

Related errors


AI-assisted analysis of dgraph-io/dgraph@759e242be6 (2026-09-01). Data as JSON: /api/errors/be28d003fd26d2a7. Report an issue: GitHub.