grpc-dotnet: Interceptor not being called
Hi,
I am trying to create a grpc interceptor that will add a bearer token to the request header on every call if it is available. This is in blazor wasm with pre-rendering and my grpc package versions are 2.37.0
My interceptor code
public class GrpcAuthInterceptor : Interceptor
{
private readonly string _apiUrl;
private readonly string[] _scopes = new[] { "somescope" };
private readonly AuthenticationStateProvider _authenticationStateProvider;
public GrpcAuthInterceptor(string apiUrl, AuthenticationStateProvider authenticationStateProvider)
{
_apiUrl = apiUrl;
_authenticationStateProvider = authenticationStateProvider;
}
public override AsyncClientStreamingCall<TRequest, TResponse> AsyncClientStreamingCall<TRequest, TResponse>(
ClientInterceptorContext<TRequest, TResponse> context,
AsyncClientStreamingCallContinuation<TRequest, TResponse> continuation)
{
Console.WriteLine("In add async client streaming call");
AddCallerMetadata(ref context);
return continuation(context);
}
private void AddCallerMetadata<TRequest, TResponse>(ref ClientInterceptorContext<TRequest, TResponse> context)
where TRequest : class
where TResponse : class
{
Console.WriteLine("In add caller metadata");
var headers = context.Options.Headers;
var authState = _authenticationStateProvider.GetAuthenticationStateAsync().GetAwaiter().GetResult();
var user = authState.User;
Console.WriteLine("grabbing a user");
var token = user.Claims.FirstOrDefault(a => a.Type == "access_token")?.Value;
Console.WriteLine($"{user.Claims.Select(_ => _.Value)}");
// Call doesn't have a headers collection to add to.
// Need to create a new context with headers for the call.
if (headers == null)
{
headers = new Metadata();
var options = context.Options.WithHeaders(headers);
context = new ClientInterceptorContext<TRequest, TResponse>(context.Method, context.Host, options);
}
// Add caller metadata to call headers
headers.Add("grpc-internal-encoding-request", "gzip");
Console.WriteLine("adding token");
headers.Add("Authorization", $"Bearer {token}");
}
}
I add the interceptor to DI with this line of code
services.AddSingleton(new GrpcAuthInterceptor(apiUrl, services.BuildServiceProvider().GetService<AuthenticationStateProvider>()));
I add the interceptor to the grpc client like
serviceCollection
.AddGrpcClient<SomeClient.Client>("clientname", options =>
{
options.Address = new Uri(apiUrl);
})
.AddInterceptor<GrpcAuthInterceptor>()
.ConfigureChannel(options =>
{
options.ServiceConfig = new ServiceConfig { MethodConfigs = { defaultMethodConfig } };
})
.ConfigurePrimaryHttpMessageHandler(() =>
{
var handler = new GrpcWebHandler(GrpcWebMode.GrpcWeb, new HttpClientHandler());
return handler;
});
I can see the constructor of the interceptor being called but no other methods are called. Any help is appreciated thank you!
About this issue
- Original URL
- State: closed
- Created 3 years ago
- Comments: 15 (4 by maintainers)
Although it is called “AddCallCredentials”, you can set whatever headers you want in it with async + DI.
@CoryKoehler FYI, prior to 2.46.0-pre1, this is the accepted way of doing it: (https://github.com/grpc/grpc-dotnet/issues/1682#issuecomment-1097812953)
The problem is you have to instantiate a new DI scope every time, which has its own problems. But at least it gets you there. I’m using Blazor WASM as well.
@CoryKoehler Just got a response from the team yesterday that they have added a way to do this properly using
AddCallCredentials
in 2.46.0-pre1: (https://github.com/dotnet/AspNetCore.Docs/pull/25734/commits/1e9bb3ba38f68021aeebebb45bc83c7d1dba9d60)It’s not a generic way to modify the headers asynchronously in an interceptor, but solves the specific use case of setting up the call credentials.