grpc-dotnet + Blazor sets Safari and Firefox User-Agent to "grpc-dotnet/$assemblyVersion"
See original GitHub issueDescribe the bug
When using grpc-dotnet and Blazor together to call a GRPC API, the User-Agent is set to “grpc-dotnet/$assemblyVersion” in Safari and Firefox. In Chrome and Edge it is the actual browser User-Agent.
https://docs.microsoft.com/en-us/aspnet/core/grpc/services?view=aspnetcore-5.0 for example describes how to read the User-Agent:
public override Task<ExampleResponse> UnaryCall(ExampleRequest request, ServerCallContext context)
{
var userAgent = context.RequestHeaders.GetValue("user-agent");
// ...
return Task.FromResult(new ExampleResponse());
}
(Migrated from https://github.com/dotnet/AspNetCore.Docs/issues/21178)
To Reproduce
Use GRPC with Blazor as described at https://docs.microsoft.com/en-us/aspnet/core/grpc/browser?view=aspnetcore-5.0 and look at the traffic in Safari. The User-Agent will be for example “grpc-dotnet/2.34.0.0”.
You can also check out https://our.gatekeeper.page in Safari or Firefox and look at the request to the “WhoAmI” endpoint to see the header being wrong. The code for this can be found at https://github.com/getgatekeeper/server.
The Blazor example from https://github.com/grpc/grpc-dotnet/tree/master/examples/Blazor should also have the same issue.
The issue seems potentially related to the following piece of code in Grpc.Net.Client/Internal/GrpcCall.cs. I wonder if Chrome/Edge just ignore the header being overwritten whilst Safari and Firefox obeys it:
// User agent is optional but recommended.
headers.TryAddWithoutValidation(GrpcProtocolConstants.UserAgentHeader, GrpcProtocolConstants.UserAgentHeaderValue);
Test plan
| Browser | Sends correct User-Agent | Screenshot |
|---|---|---|
| Safari | ❌ | ![]() |
| Firefox | ❌ | ![]() |
| Chrome | ✅ | ![]() |
| Edge | ✅ | ![]() |
Issue Analytics
- State:
- Created 3 years ago
- Reactions:1
- Comments:8 (8 by maintainers)





Top Related StackOverflow Question
SignalR sets the “X-SignalR-User-Agent” header.
https://github.com/dotnet/aspnetcore/blob/020145ded2fd7ea4657f220e000d64d41232bec3/src/SignalR/clients/ts/signalr/src/Utils.ts#L201
I believe the reason we don’t set “User-Agent” is because it used to be a forbidden header but no longer is. Also, Chrome just drops the header? https://bugs.chromium.org/p/chromium/issues/detail?id=571722
gRPC fixed. Re-opening for SignalR.