The article looks at managing user delegated access tokens for a downstream API in an ASP.NET Core web application. There are many ways of implementing this, all with advantages and disadvantages. The tokens are requested from an OpenID Connect server using the recommended standards. In this blog, the UI access token from the application authentication is re-used for the downstream API.
Code: https://github.com/damienbod/token-mgmt-ui-delegated-direct
Setup
The solution uses a secure downstream API and requires user delegated access tokens for access. The UI application is implemented using ASP.NET Core and razor pages. The UI application authenticates against an OpenID Connect server implemented using OpenIddict. The application client is implemented using an OpenID Connect confidential client and the OpenID Connect code flow with PKCE. This flow returns an access token which is used for the downstream API.

What must an application manage?
An access token management solution must ensure that tokens are securely stored per user session for user delegated tokens and updated after each UI authentication or refresh. The solution should be robust to handle token expiration, function seamlessly after restarts, and support multi-instance deployments. Additionally, it must effectively manage scenarios involving invalid or missing access tokens.
Properties of token management in the solution setup:
- The access token is persisted per user session
- The token expires
- The token needs to be persisted somewhere safely
- The token must be replaced after each UI authentication (per user)
- The solution must work after restarts
- The solution must work for multiple instances when deployed to multi-instance deployments.
- The solution must handle invalid access tokens or missing access tokens
Implementation example using Duende Token Management
The Duende Token Management OpenIdConnect Nuget package can be used to implement these requirements for user delegated access tokens. This is not the only way to do this and can be implemented in numerous different ways. With this package, the AddOpenIdConnectAccessTokenManagement can be used to add the token management.
builder.Services.AddOpenIdConnectAccessTokenManagement();
The different HTTP requests or the Razor pages can use the GetUserAccessTokenAsync method to get the access token for each user and session. The SaveTokens is set to true to persist the tokens in the session using a secure cookie per default. This is an option in the AddOpenIdConnect method. The defined scope is used to select the access token.
// token expires, token managment required
var accessToken = await HttpContext.GetUserAccessTokenAsync(
new UserTokenRequestParameters
{
Scope = "myscope"
});
The AddUserAccessTokenHttpClient method can be used to add a named HttpClient client for the access token and the specific API.
builder.Services.AddUserAccessTokenHttpClient("profileClient",
configureClient: client =>
{
client.BaseAddress = new Uri(profileApiBaseUrl!);
});
This client can then be used to access the API resource using the access token.
var client = _clientFactory.CreateClient("profileClient");
var response = await client.GetAsync("api/Profiles/photo");
if (response.IsSuccessStatusCode)
{
var data = await response.Content.ReadAsStringAsync();
if (data != null)
return data;
return string.Empty;
}
When the applications are started, the access token can be used to request data from the downstream API.
Notes
In follow up blogs, I will look at the different ways and the different types of strategies which are used to implement token management in ASP.NET Core web applications.
- OAuth Client credentials tokens in web applications
- Microsoft.Identity.Web delegated access tokens & OBO access tokens
- Microsoft.Identity.Client application tokens
- Azure SDK tokens
- Handling multiple access tokens
- OAuth Token Exchange for downstream user delegated access tokens
Links
Duende.AccessTokenManagement.OpenIdConnect
https://learn.microsoft.com/en-us/aspnet/core/security/authentication/social/additional-claims