{"record":{"id":"68fc6355786140e1","repo":"jaegertracing/jaeger","slug":"malformed-token-multiple-tokens-found","errorCode":null,"errorMessage":"malformed token: multiple tokens found","messagePattern":"malformed token: multiple tokens found","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"internal/auth/bearertoken/grpc.go","lineNumber":37,"sourceCode":"}\n\nfunc (tss *tokenatedServerStream) Context() context.Context {\n\treturn tss.context\n}\n\n// extract bearer token from the metadata\nfunc ValidTokenFromGRPCMetadata(ctx context.Context, bearerHeader string) (string, error) {\n\tmd, ok := metadata.FromIncomingContext(ctx)\n\tif !ok {\n\t\treturn \"\", nil\n\t}\n\n\ttokens := md.Get(bearerHeader)\n\tif len(tokens) < 1 {\n\t\treturn \"\", nil\n\t}\n\tif len(tokens) > 1 {\n\t\treturn \"\", errors.New(\"malformed token: multiple tokens found\")\n\t}\n\treturn tokens[0], nil\n}\n\n// NewStreamServerInterceptor creates a new stream interceptor that injects the bearer token into the context if available.\nfunc NewStreamServerInterceptor() grpc.StreamServerInterceptor {\n\treturn func(srv any, ss grpc.ServerStream, _ *grpc.StreamServerInfo, handler grpc.StreamHandler) error {\n\t\tif token, _ := GetBearerToken(ss.Context()); token != \"\" {\n\t\t\treturn handler(srv, ss)\n\t\t}\n\n\t\tbearerToken, err := ValidTokenFromGRPCMetadata(ss.Context(), Key)\n\t\tif err != nil {\n\t\t\treturn err\n\t\t}\n\n\t\treturn handler(srv, &tokenatedServerStream{\n\t\t\tServerStream: ss,","sourceCodeStart":19,"sourceCodeEnd":55,"githubUrl":"https://github.com/jaegertracing/jaeger/blob/806f4447841ecdb60519f408b004a599d515f437/internal/auth/bearertoken/grpc.go#L19-L55","documentation":"ValidTokenFromGRPCMetadata returns this error when the gRPC metadata contains more than one value under the authorization/bearer header. A single bearer token is expected; multiple values indicate a malformed or conflicting auth header set.","triggerScenarios":"A client (or proxy/metadata forwarding) sends the bearerHeader metadata key twice, e.g. attaching authorization metadata both manually and via an interceptor; md.Get returns len(tokens) > 1 and the function errors.","commonSituations":"Composed interceptors that each inject the token into the same metadata key; HTTP-to-gRPC gateways duplicating the Authorization header into metadata; middleware that appends instead of replacing.","solutions":["Ensure the client sets the authorization metadata key exactly once per request (overwrite, not append)","Fix gateway/proxy config that duplicates the Authorization header into gRPC metadata","Replace with `md.Set(bearerHeader, token)` instead of `md.Append` when injecting tokens in interceptors"],"exampleFix":"// before\nmd.Append(\"authorization\", \"Bearer \"+token)\n// after\nmd.Set(\"authorization\", \"Bearer \"+token)","handlingStrategy":"validation","validationCode":"md, _ := metadata.FromIncomingContext(ctx)\nvals := md.Get(\"authorization\")\nif len(vals) > 1 {\n    return errors.New(\"authorization metadata set more than once\")\n}","typeGuard":"func singleToken(md metadata.MD, key string) (string, bool) {\n    v := md.Get(key)\n    if len(v) != 1 {\n        return \"\", false\n    }\n    return v[0], true\n}","tryCatchPattern":"token, err := bearertoken.ValidTokenFromGRPCMetadata(ctx)\nif err != nil {\n    if strings.Contains(err.Error(), \"multiple tokens found\") {\n        return status.Error(codes.InvalidArgument, \"duplicate authorization metadata\")\n    }\n    return status.Error(codes.Unauthenticated, err.Error())\n}","preventionTips":["Use md.Set (not md.Append) when injecting auth metadata","Check middleware chains for double injection","Verify gateways map Authorization headers one-to-one"],"tags":["go","grpc","authentication","bearer-token"],"backgroundTag":"duplicate-auth-header","analyzedSha":"806f4447841ecdb60519f408b004a599d515f437","analyzedAt":"2026-09-01T02:39:22.140Z","contentChangedAt":null,"schemaVersion":2},"datasetVersion":"2026-09-08T05:18:18.240Z"}