{"record":{"id":"e55276b7dbcc6137","repo":"googleapis/mcp-toolbox","slug":"invalid-jwt-token","errorCode":null,"errorMessage":"invalid JWT token","messagePattern":"invalid JWT token","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"internal/auth/generic/generic.go","lineNumber":237,"sourceCode":"// Verifies generic JWT access token inside the Authorization header\nfunc (a AuthService) GetClaimsFromHeader(ctx context.Context, h http.Header) (map[string]any, error) {\n\tif a.McpEnabled {\n\t\treturn nil, nil\n\t}\n\n\ttokenString := h.Get(a.Name + \"_token\")\n\tif tokenString == \"\" {\n\t\treturn nil, nil\n\t}\n\n\t// Parse and verify the token signature\n\ttoken, err := jwt.Parse(tokenString, a.kf.Keyfunc)\n\tif err != nil {\n\t\treturn nil, fmt.Errorf(\"failed to parse and verify JWT token: %w\", err)\n\t}\n\n\tif !token.Valid {\n\t\treturn nil, fmt.Errorf(\"invalid JWT token\")\n\t}\n\n\tclaims, ok := token.Claims.(jwt.MapClaims)\n\tif !ok {\n\t\treturn nil, fmt.Errorf(\"invalid JWT claims format\")\n\t}\n\n\t// Validate 'aud' (audience) claim\n\taud, err := claims.GetAudience()\n\tif err != nil {\n\t\treturn nil, fmt.Errorf(\"could not parse audience from token: %w\", err)\n\t}\n\n\tisAudValid := false\n\tfor _, audItem := range aud {\n\t\tif audItem == a.Audience {\n\t\t\tisAudValid = true\n\t\t\tbreak","sourceCodeStart":219,"sourceCodeEnd":255,"githubUrl":"https://github.com/googleapis/mcp-toolbox/blob/8cc6e09de2ad7b8bffc77751799585a1401a48eb/internal/auth/generic/generic.go#L219-L255","documentation":"jwt.Parse returned no error but token.Valid is false, meaning the token structurally parsed yet is not considered valid. With golang-jwt/v5 this state is rare (most invalid tokens return an error), but the library guards it explicitly and rejects the request with this message.","triggerScenarios":"jwt.Parse succeeds without error, but the resulting token's Valid flag is false during GetClaimsFromHeader — e.g. claims-type edge cases where validation did not complete normally.","commonSituations":"Tokens whose claims cannot be validated by the default validator; custom/edge-case tokens from non-standard issuers; typically indicates an unusual or hand-crafted token rather than a config problem.","solutions":["Inspect the token contents at jwt.io for unusual or missing standard claims","Obtain a fresh, normally-issued token from the authorization server","Ensure the client library issuing tokens is spec-compliant","Enable logging of the raw token header/payload to diagnose the anomaly"],"exampleFix":null,"handlingStrategy":"try-catch","validationCode":"// decode and sanity-check standard claims before sending\nclaims := decodePayload(tokenParts[1])\nif _, ok := claims[\"exp\"]; !ok {\n    return fmt.Errorf(\"token missing exp claim; likely non-compliant issuer\")\n}","typeGuard":null,"tryCatchPattern":"claims, err := authSvc.GetClaimsFromHeader(ctx, header)\nif err != nil {\n    if strings.Contains(err.Error(), \"invalid JWT token\") {\n        return nil, http.StatusUnauthorized // structurally parsed but not valid\n    }\n    return nil, http.StatusInternalServerError\n}","preventionTips":["Use a spec-compliant client library to obtain tokens","Reject hand-crafted or test tokens in production","Log the token header (never the signature) when debugging anomalies"],"tags":["go","jwt","auth","security"],"backgroundTag":"jwt-token-invalid","analyzedSha":"8cc6e09de2ad7b8bffc77751799585a1401a48eb","analyzedAt":"2026-09-05T01:10:36.887Z","contentChangedAt":"2026-09-05T01:10:36.887Z","schemaVersion":2},"datasetVersion":"2026-09-08T10:18:20.063Z"}