ASP.NET Core - OAuth 2.0 Client Access Token Management

OAuth 2.0 client access token management in an ASP.NET Core application

commit 17ac1b5 · authored · 3 min read

ASP.NET Core - OAuth 2.0 Client Access Token Management

In a microservice world, the machine (microservice A) to machine (microservice B) communications can be secured using an OAuth 2.0 compatible token service, IdentityServer in our case. i.e To successfully call microservice B, microservice A needs to get an access token first via client credentials grant type from the IdentityServer with the right scope for the operation.

  • microservice A calls IdentityServer to get an access token.
  • microservice A then calls microservice B with the access token in the authorization header (bearer token).
  • microservice B validates the access token, responds to microservice A with a valid response.

The above steps are fine for a single call, but in case of multiple calls from A to B, A doesn’t need to get an IdentityServer token every time since each token has its validity, so basically, A can reuse the token until it expires.

For the token reusing, you don’t need to implement the caching and refreshing token logic anywhere since some good people who are maintaining IdentityModel.AspNetCore already done that. All we need to do is set up it, and consume it.

The library will take care of the following,

  • caching abstraction for access tokens
  • automatic renewal of expired access tokens
  • token lifetime automation for HttpClient

let’s jump into the setup. Following are our assumptions,

  • microservice B has endpoints,
    • POST /orders and it requires IdentityServer token with orders.write scope to create new orders,
    • and to fetch the orders GET /orders endpoint, the scope for that one is orders.read.
  • microservice A has valid client credentials configured on the IdentityServer with the above scopes added to the allowed scopes. i.e microservice A is allowed to call the microservice B.

So let’s configure microservice A,

  • Install IdentityModel.AspNetCore package

In the Startup.cs > ConfigureServices

// Setup token management service
services.AddAccessTokenManagement(options =>
{
options.Client.Clients.Add(AppConsts.StsClientName, new ClientCredentialsTokenRequest
{
Address = $"{Configuration.GetValue<string>("Authentication:Sts:BaseUrl")}/connect/token", // Token service (IdentityServer) base URL
ClientId = Configuration.GetValue<string>("Authentication:Sts:ClientId"),
ClientSecret = Configuration.GetValue<string>("Authentication:Sts:ClientSecret"),
Scope = $"{AppConsts.OrdersWriteScope} {AppConsts.OrdersReadScope}" // Any number of scopes, space separated
});
});
// Adds a named HTTP client for the factory that automatically sends the client access token
services.AddClientAccessTokenClient(AppConsts.StsClientName, AppConsts.StsClientName, client => client.BaseAddress = new Uri(Configuration.GetValue<string>("ApiBaseUrl"))); // microservice B base URL

Here we setup the token management service and a named HttpClient that uses the same. Also you can observe, we moved the static string params to a AppConsts.cs file,

public class AppConsts
{
public const string OrdersWriteScope = "orders.write";
public static string OrdersReadScope = "orders.read";
public static string StsClientName = "microservice_a_api_client";
}

And the configurations like client credentials, token service endpoint, and rest are kept in the appsettings.json or somewhere more private like Azure App Configuration, keyvault, and loaded to the aspnetcore configurations.

"ApiBaseUrl": "https://microservice-b.com",
"Authentication": {
"Sts": {
"BaseUrl": "https://my-identityserver.com",
"ClientId": "microservice_a_api",
"ClientSecret": ""
}
},

Configuration is done, now let’s consume the HttpClient. Here I’m using Flurl to make the HTTP request, if you prefer direct HttpClient usage, you can do that way. You don’t need to do anything special to get the access token since it is already taken care of.

using Flurl.Http;
public class GetOrdersQueryHandler : IRequestHandler<SomeInput, SomeOutput>
{
private readonly IFlurlClient _flurlClient;
public GetOrdersQueryHandler(IHttpClientFactory httpClientFactory)
{
var httpClient = httpClientFactory.CreateClient(AppConsts.StsClientName);
_flurlClient = new FlurlClient(httpClient);
}
public async Task<SomeOutput> Handle(SomeInput request, CancellationToken cancellationToken)
{
return await _flurlClient
.Request($"/orders")
.GetJsonAsync<SomeOutput>(cancellationToken);
}
}

As you can see, we use the named httpClient, and that client is already configured to have the access token with the scopes. That’s it. You can use the same way to call the create order endpoint since the client has an access token with both scopes.

Additional Resources

local graph · open full graph

"ASP.NET Core - OAuth 2.0 Client Access Token Management" is connected to the topics ASP.NET Core, API Management, IdentityServer and related to 6 other entries. .NET Core API Gateway Ocelot - Logging HTTP Requests & Response Including Headers & Body .NET Core API Gateway Ocelo… ASP.NET Core - Using Mutliple Authentication Schemes ASP.NET Core - Using Mutlip… Serilog - Console Sink Themes Serilog - Console Sink Them… Azure DevOps Build - Could not locate the assembly Azure DevOps Build - Could … ASP.NET Core - Return 500 (Internal Server Error) or any other Status Code from API ASP.NET Core - Return 500 (… Docker - SQL Error on ASP.NET Core Alpine Docker - SQL Error on ASP.N… ASP.NET Core #aspnet-core API Management #api-management IdentityServer #identityserver ASP.NET Core - OAuth 2.0 Client A…

webmentions · 1 mention

  • Someone · Sep 19, 2022 · mention

    If you need information about asp net 2 Accesso , here’s what we’ve prepared for you. If something goes wrong, when you contact the brand’s customer service for help, the only trick is: patience. Describe your problem in detail and don’t miss any details. The ASP.NET 2.0 Page Model | Microsoft Docs https://docs.microsoft.com/en-us/aspnet/web-forms/… Apr 09, 2020 · The code-behind class in ASP

comments

loading discussion…