{"record":{"id":"a8cfd48dca53afd2","repo":"googleapis/mcp-toolbox","slug":"could-not-parse-audience-from-token-w","errorCode":null,"errorMessage":"could not parse audience from token: %w","messagePattern":"could not parse audience from token: %w","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"internal/auth/generic/generic.go","lineNumber":248,"sourceCode":"\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\n\t\t}\n\t}\n\n\tif !isAudValid {\n\t\treturn nil, fmt.Errorf(\"audience validation failed: expected %s, got %v\", a.Audience, aud)\n\t}\n\n\treturn claims, nil\n}\n\n// MCPAuthError represents an error during MCP authentication validation.","sourceCodeStart":230,"sourceCodeEnd":266,"githubUrl":"https://github.com/googleapis/mcp-toolbox/blob/8cc6e09de2ad7b8bffc77751799585a1401a48eb/internal/auth/generic/generic.go#L230-L266","documentation":"The JWT parsed successfully but its 'aud' (audience) claim could not be read via MapClaims.GetAudience(). The library requires an audience claim to verify the token was issued for this toolbox audience. GetAudience fails when the claim is absent or is not a string or array of strings.","triggerScenarios":"GetClaimsFromHeader verifies a token whose claims lack 'aud' or whose 'aud' has an unexpected JSON type (number, object, null), then calls claims.GetAudience() which returns an error that is wrapped into this message.","commonSituations":"Identity-provider tokens minted without an audience (e.g. service-account tokens), tokens with 'aud' as a non-string JSON value, or tokens intended for a different product that omit the claim.","solutions":["Re-issue the token including an 'aud' claim matching the audience configured on the auth service.","Check the token payload at jwt.io and fix the 'aud' type to a string or array of strings.","If your IdP cannot add 'aud', configure the audience correctly or use a token flow that includes it (e.g. request scope/audience when exchanging credentials)."],"exampleFix":"// before\n{\"iss\":\"https://idp.example.com\",\"sub\":\"user1\"}\n// after\n{\"iss\":\"https://idp.example.com\",\"sub\":\"user1\",\"aud\":\"toolbox-audience\"}","handlingStrategy":"validation","validationCode":"payload := decodeJWTPayload(tokenString) // base64 decode part 2\naud, ok := payload[\"aud\"]\nif !ok {\n    return fmt.Errorf(\"token has no aud claim; re-request with audience parameter\")\n}\nswitch aud.(type) {\ncase string, []any:\ndefault:\n    return fmt.Errorf(\"aud must be string or array, got %T\", aud)\n}","typeGuard":"func hasValidAud(claims map[string]any) bool {\n    a, ok := claims[\"aud\"]\n    if !ok { return false }\n    switch v := a.(type) {\n    case string:\n        return v != \"\"\n    case []any:\n        return len(v) > 0\n    default:\n        return false\n    }\n}","tryCatchPattern":"claims, err := svc.GetClaimsFromHeader(ctx, header)\nif err != nil {\n    var audErr *jwt.AudienceError\n    if errors.As(err, &audErr) || strings.Contains(err.Error(), \"could not parse audience\") {\n        return http.StatusUnauthorized // token lacks usable aud claim\n    }\n    return http.StatusInternalServerError\n}","preventionTips":["Always request tokens with an explicit audience/resource parameter","Verify tokens at jwt.io include a string-or-array aud claim","Document the required aud claim for your client-credential flows"],"tags":["jwt","auth","audience"],"backgroundTag":"jwt-missing-audience-claim","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"}