Search code examples
asp.net-coregrpc

How could do the authentication and authorization in a gRPC service in a ASP Core application?


I have a gRPC service that is hosted in an ASP Core NET 7 application.

I am reading how to use JWT to authenticate and authorize a client at ASP Core level, but I don't know how to do it in the gRPC level.

My application has this strcuture: Asp Core --> gRPC --> application layer

Asp Core just host the gRPC service, but it seems it handle the authentication too. But in the gRPC service I need to authenticate the user to can get the ID of the client to can get some data.

For example, I have this method in the gRPC service:

class MyBankService
{
    BankAccount GetBankAccountOfClient(long clientId)
    {
        Client myClient = _clientsRepository.GetClient(username, password);

        return myApplicationSerivice.GetBankAccountOfClient(myClient.Id);
    }
}

With this example, I try to show how I need to get the Id of the client from the database that correspond to the credentials sending from the client to can get the bank account of the client.

I don't know if I should to have a login method in my server to get the id and to have a dictionary with the JWT token and relate it with the user, something like that:

class MyBankService
{
    Dictionary<object, long> _clientIds = new Dictionary<object, long>();


    void Login(string paramUserName, string paramPassword)
    {
        Client myClient = _clientRepository.GetClient(paramUserName, paramPassword);

        string myHashedPassword = HasPassword(paramPassword);

        if(myHashedPassword == myClient.HashedPassword)
        {
             _dictionary.Add(token, myClient.Id); //where to get the token?
        }
        else
        {
             throw new Exception("User not valid.");
        }
    }



   BankAccount GetBankAccountOfClient(object token)
   {
       //from where to get the token???
       if(_dictionary.ContainsKey(token) == false) throw exception();

       //if valid because it can be expired or another reason.
       if(CheckIsTokenIsValid(token) == false) throw exception();



       return applicationService.GetBankAccountOfClient(_dictionary[token].Id);
   }
}

But if this is a correct way, from where to get the token? And when the token is expired, I would have to delete from dictionary, so I should to do a maintenance of the dictionary, so it is more work. And if I have many users, is it a good idea to have a big dictionary with all the tokens and Ids?

I am sure that there should be another better way to handle all this, but I don't know alternatives. Perhaps with interceptors?

So in summary, I would like to know the way to handle the authorization and how to get the needed data of the client to filter data and ensure I will not send data that the client should see.

Thanks.


Solution

  • Token handle (JWT)

    JWT token perfectly fit to your needs:

    • You decide which fields to store in
    • All your private data contained in issued token secured (in private claims only)
    • On request with JWT handle, you can decrypt data in token
    • No server storage required
    • Data in JWT can be shared between servers (so dont define sensetive information in public claims)
    • Easy .NET setup

    How to setup:

    • Add nuget
      PM> Install-Package Microsoft.AspNetCore.Authentication.JwtBearer
      
    • Configure JWT settings (for example in appsettings.json)
        
    
        "Jwt": {
                "Issuer": "https://joydipkanjilal.com/",
                "Audience": "https://joydipkanjilal.com/",
                "Key": "This is a sample secret key - please don't use in production environment.'"
              }
    
    
    • Configure authentication in the Program.cs (or Startup.cs) file
      
      builder.Services.AddAuthentication(options =>
      {
          options.DefaultAuthenticateScheme = JwtBearerDefaults.AuthenticationScheme;
          options.DefaultChallengeScheme = JwtBearerDefaults.AuthenticationScheme;
          options.DefaultScheme = JwtBearerDefaults.AuthenticationScheme;
      });
      
      
    - Configure Auth services
    
    builder.Services.AddAuthorization();
    ...
    app.UseAuthentication();
    app.UseAuthorization();
    
    Setup is finished, you are ready for authentication implementation!  
    
    I recommend [this][1] article to get started with JWT auth in .NET. 
    More about JWT in common - [link][2].
    <h1>gRPC Auth</h1>
    
    According to [Documentation][3], you can configure  authentication/authorization in gRPC services through for these services.
    
    > Interceptors are a gRPC concept that allows apps to interact with
    > incoming or outgoing gRPC calls. They offer a way to enrich the
    > request processing pipeline.
    
    In other words you have to:  
    - create new AuthInterceptor  
    - override `AsyncUnaryCall` method with authentication logic  
    
    Also check similar [question][4] on stackoverflow with token setup on grpcClient.
    
    
      [1]: https://www.infoworld.com/article/3669188/how-to-implement-jwt-authentication-in-aspnet-core-6.html
      [2]: https://jwt.io/introduction
      [3]: https://learn.microsoft.com/en-us/aspnet/core/grpc/interceptors?view=aspnetcore-7.0
      [4]: https://stackoverflow.com/questions/68442239/c-sharp-grpc-client-interceptor-set-authorization-header