Version 5.x has been out of support since December 13, 2022, and this corresponding section of the documentation is no longer maintained. We strongly recommend upgrading to a supported version.

Token Management

The token management library does essentially two things:

  • stores access and refresh tokens in the current session
  • refreshes access tokens automatically at the token service when needed

Both aspects can be customized.

Token service communication

The token management library uses a named HTTP client from the HTTP client factory for all token service communication. You can provide a customized HTTP client yourself using the well-known name after calling AddBff:

services.AddHttpClient(AccessTokenManagementDefaults.BackChannelHttpClientName, configureClient => { ... });

You can also supply client assertions to the token management library. See this sample for JWT-based client authentication.

Custom token storage

We recommend to use the default storage mechanism, as this will automatically be compatible with the Duende.BFF server-side sessions.

If you do not use server-side sessions, then the access and refresh token will be stored in the protected session cookie. If you want to change this, you can take over token storage completely.

This would involve two steps

  • turn off the SaveTokens flag on the OpenID Connect handler and handle the relevant events manually to store the tokens in your custom store
  • implement and register the IdentityModel.AspNetCore.AccessTokenManagement.IUserAccessTokenStore interface

The interface is responsible to storing, retrieving and clearing tokens for the automatic token management:

public interface IUserAccessTokenStore
{
    /// <summary>
    /// Stores tokens
    /// </summary>
    /// <param name="user">User the tokens belong to</param>
    /// <param name="accessToken">The access token</param>
    /// <param name="expiration">The access token expiration</param>
    /// <param name="refreshToken">The refresh token (optional)</param>
    /// <param name="parameters">Extra optional parameters</param>
    /// <returns></returns>
    Task StoreTokenAsync(ClaimsPrincipal user, string accessToken, DateTimeOffset expiration, string refreshToken = null, UserAccessTokenParameters parameters = null);

    /// <summary>
    /// Retrieves tokens from store
    /// </summary>
    /// <param name="user">User the tokens belong to</param>
    /// <param name="parameters">Extra optional parameters</param>
    /// <returns>access and refresh token and access token expiration</returns>
    Task<UserAccessToken> GetTokenAsync(ClaimsPrincipal user, UserAccessTokenParameters parameters = null);

    /// <summary>
    /// Clears the stored tokens for a given user
    /// </summary>
    /// <param name="user">User the tokens belong to</param>
    /// <param name="parameters">Extra optional parameters</param>
    /// <returns></returns>
    Task ClearTokenAsync(ClaimsPrincipal user, UserAccessTokenParameters parameters = null);
}