Featured

gRPC Authenticate and Authorize (Server & Client)

Last modified: May 24, 2022

In this article, we learn how to create a gPRC client to authenticate a gRPC Server/Resources

We require

1. gRPC Server

1.1. Create a project

project

project

project

1.2 Install Nuget Package

Microsoft.AspNetCore.Authentication.JwtBearer

project

1.3 JWT Appsetting.json

"Jwt": { "Key": "ertwet3245sgf2342werwergww4352345", "Issuer": "https://localhost:7096/", "Audience": "https://localhost:7006/" }

1.4 Configure JWT Token Authenticate and Authorize in Program.cs

using gRPCServer; using gRPCServer.Services; using Microsoft.AspNetCore.Authentication.JwtBearer; using Microsoft.AspNetCore.Authorization; using Microsoft.IdentityModel.Tokens; using System.Text; var builder = WebApplication.CreateBuilder(args); // Additional configuration is required to successfully run gRPC on macOS. // For instructions on how to configure Kestrel and gRPC clients on macOS, visit https://go.microsoft.com/fwlink/?linkid=2099682 // Add services to the container. builder.Services.AddGrpc(); builder.Services.AddAuthentication(JwtBearerDefaults.AuthenticationScheme).AddJwtBearer(opt => { opt.TokenValidationParameters = new() { ValidIssuer = builder.Configuration["Jwt:Issuer"], ValidAudience = builder.Configuration["Jwt:Audience"], IssuerSigningKey = new SymmetricSecurityKey(Encoding.UTF8.GetBytes(builder.Configuration["Jwt:Key"])) }; }); builder.Services.AddAuthorization(); var app = builder.Build(); // Configure the HTTP request pipeline. app.MapGrpcService<GreeterService>(); app.MapGrpcService<MessageService>(); //register MessageService app.MapGet("/", () => "Communication with gRPC endpoints must be made through a gRPC client. To learn how to create a client, visit: https://go.microsoft.com/fwlink/?linkid=2086909"); app.UseAuthentication(); ; app.UseAuthorization(); app.Run();

1.5 Create a Proto file and set it server

project

We create a simple method to print the message to console

syntax = "proto3"; option csharp_namespace = "gRPCServer"; package message; service MessageProvider{ rpc PrintMessage(Empty) returns (Empty); } message Empty {}

project

1.6 Create a Message Service, the implementation of Proto File

  • Create MessageService class file and paste with the following code. Basically, we are protecting the endpoints and check if user is authenticate, if yes print user's name.
using Grpc.Core; using Microsoft.AspNetCore.Authorization; namespace gRPCServer { [Authorize] public class MessageService: MessageProvider.MessageProviderBase { public override Task<Empty> PrintMessage(Empty request, ServerCallContext context) { var user = context.GetHttpContext().User; Console.WriteLine(user.Identity.Name); return Task.FromResult<Empty>(new Empty()); ​ } } }

Consuming gRPC Server

2. Client (ASP.NET 6 MVC)

  • Create an ASP.NET 6 MVC project
  • Copy the message.proto from server and paste it to client
  • rename csharp_namespace to gRPC_Client
  • Right click message.proto as mark it as client

project project project

2.1 Install Nuget Packages

project project project project

2.2 Get JWT Token

  • Get JWT token from JWT Auth Server by passing username and password
  • Get it in Home Controller, Index Action
  • create a UserDto (record UserDto(string UserName, string Password);)

Method 1: Make use of MetaData header to pass thw JWT token

using (var httpClient = new HttpClient()) { var user = new UserDto(UserName: "[email protected]", Password: "admin"); var json = JsonConvert.SerializeObject(user); var content = new StringContent(json, Encoding.UTF8, "application/json"); using (var response = await httpClient.PostAsync("https://localhost:7096/auth/getToken", content)) { var token = await response.Content.ReadAsStringAsync(); token = token.Substring(1, token.Length - 2); var headers = new Metadata(); headers.Add("Authorization", $"Bearer {token}"); string GrpcChannelURL = "https://localhost:7006"; using var channel = GrpcChannel.ForAddress(GrpcChannelURL); var message = new MessageProviderClient(channel); var products = message.PrintMessage(new Empty { }, headers); } }

project

Test

project

Method 2: Make use of service (DI)

Install an additional Nuget Package for this method

project

Create a class and interface to get token from JWT Auth Server

record UserDto(string UserName, string Password); public interface ITokenProvider { Task<string> GetToken(); } public class TokenProvider : ITokenProvider { private string _token; public async Task<string> GetToken() { if (string.IsNullOrEmpty(_token)) { using (var httpClient = new HttpClient()) { //in your pass username from User UI to this class var user = new UserDto(UserName: "[email protected]", Password: "admin"); var json = JsonConvert.SerializeObject(user); var content = new StringContent(json, Encoding.UTF8, "application/json"); using (var response = await httpClient.PostAsync("https://localhost:7096/auth/getToken", content)) { var token = await response.Content.ReadAsStringAsync(); _token = token.Substring(1, token.Length - 2); } } } return _token; } }

Register Auth DI and configure gRPC client client factorym with authentication

builder.Services.AddScoped<ITokenProvider, TokenProvider>(); builder.Services.AddGrpcClient<MessageProvider.MessageProviderClient>(o => { o.Address = new Uri("https://localhost:7006"); }) .AddCallCredentials(async (context, metadata, serviceProvider) => { var provider = serviceProvider.GetRequiredService<ITokenProvider>(); var token = await provider.GetToken(); metadata.Add("Authorization", $"Bearer {token}"); });

Home Controller

project

Test

project