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)

Most upvoted comments

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.

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.