JWT authentication for gRPC
In a recent blog post, I described how to add JWT authentication to an ASP.NET Core Web API project. This time I'm doing the same for a gRPC project. To test the authentication, I'm using similar Web API integration tests, with slightly modified setup to make them work with gRPC.
Again, I'm generating the JWT in tests using Jwt.Net NuGet package:
var token = JwtBuilder
.Create()
.WithAlgorithm(new RS256Algorithm(CreateCertificate()))
.AddClaim(ClaimName.Issuer, "https://localhost:5000")
.AddClaim(ClaimName.Audience, "web-api-oauth-test")
.AddClaim(ClaimName.Subject, "test")
.AddClaim(
ClaimName.ExpirationTime,
DateTimeOffset.UtcNow.AddHours(1).ToUnixTimeSeconds()
)
.Encode();
This token then needs to be added as authorization metadata to the request:
var client = new Greeter.GreeterClient(channel);
var request = new HelloRequest { Name = "World" };
var metadata = new Metadata { { "Authorization", $"Bearer {token}" } };
var response = await client.SayHelloAsync(request, metadata);
When instantiating the gRPC channel in integration tests, it's important to provide the HTTP client created by the WebApplicationFactory
class and the server's base address, otherwise the client will fail to connect:
factory = new WebApplicationFactory<Program>();
var options = new GrpcChannelOptions { HttpClient = factory.CreateClient() };
channel = GrpcChannel.ForAddress(factory.Server.BaseAddress, options);
In the gRPC server project, the AddJwtBearer
method from the Microsoft.AspNetCore.Authentication.JwtBearer NuGet package is used to configure the JWT authentication:
builder
.Services.AddAuthentication(JwtBearerDefaults.AuthenticationScheme)
.AddJwtBearer(options =>
{
options.Audience = "web-api-oauth-test";
options.TokenValidationParameters = new TokenValidationParameters
{
ValidIssuer = "https://localhost:5000",
SignatureValidator = (token, parameters) => new JsonWebToken(token)
};
});
The JWT configuration is identical to the one used for a Web API project. You also need to add the Authorize
attribute to the services or methods implementing the endpoints you want require valid authorization for:
[Authorize]
public class GreeterService : Greeter.GreeterBase
{
/// ...
}
However, in a gRPC project, authorization middleware is not added to the pipeline by default, so you have to do it yourself:
app.UseAuthentication();
app.UseAuthorization();
And also register the authorization services with dependency injection:
builder.Services.AddAuthorization();
To see full source code for a working sample application, check my GitHub repository. The final commit contains all the changes I had to make to the sample project created from the ASP.NET Core gRPC Service project template to make authentication with JWT work.
Authentication isn't shown all that often in gRPC samples, but since the server is ASP.NET Core based just like Web API, the same approach can be used to implement it.