I have a .net 8 webApi used for logging in to a secure site using OpenIdConnect.
We are using Duende nuget packages to handle DPoP. This works great, but we have a workflow where we enrich the acccess token with an extra claim (RAR.
We need to use the userId from the initial login and use this value as a parameter in our backend to build the “RAR” object used to populate the extra Claim. We update our login by calling RequestRefresTokenAsync() from a httpClient.
var refreshTokenResult = await httpClient.RequestRefreshTokenAsync(new RefreshTokenRequest
{
ClientCredentialStyle = ClientCredentialStyle.PostBody,
ClientAssertion = clientAssertion, //This ClientAssertion contains the Extra Claim
Address = _appSettings.HelseId.TokenEndpoint,
ClientId = _appSettings.HelseId.ClientId,
RefreshToken = token.RefreshToken,
Method = HttpMethod.Post,
GrantType = OidcConstants.GrantTypes.RefreshToken,
DPoPProofToken = ClientAssertionBuilder.CreateDPoPProof(_appSettings.HelseId.RsaKey, _appSettings.HelseId.TokenEndpoint, "POST", dPoPNonce: dPoPNonce, token.AccessToken)
});
My refreshTokenResult contains AccessToken with the extra claim and I can use this AccessToken to perform what needs to be done.
Unfortunately I am unable to use Duendes library that handles DPoP and automatically manages AccessTokens, handles Token expiry and refreshes etc by injecting a named HttpClient with “.AddUsesrAccessTokenHandler”
I would like to use this:
builder.Services.AddHttpClient("MyApi")
.AddUserAccessTokenHandler();
But, unfortunately, if I use the “MyApi” httpClient my AccessToken which is refreshed and enriched with the extra Claim will get replaced by the initial AccessToken missing the extra Claim.
How can I either update the accesstokenManagement from Duende with my new token, but preferably extendt the service to add my extra Claim? The problem is, I do not have the extra Claim untill the user is authenticated and I have read a parameter to the controller/endpoint the client request.
I have tried to implement my own IClientAssertionService
// Use client assertion for automatic refresh of tokens
builder.Services.AddScoped<IClientAssertionService, ClientAssertionService>();
public Task<ClientAssertion?> GetClientAssertionAsync(string? clientName = null, TokenRequestParameters? parameters = null)
{
var rarValue = FindCookie(_httpContextAccessor.HttpContext.Response.Headers, "rar");
string assertionValue = string.Empty;
if (!string.IsNullOrWhiteSpace(rarValue ))
{
_logger.LogDebug("GetClientAssertionAsync Create ClientAssertion with RAR");
var hcpInfo = JsonSerializer.Deserialize<HcpInformation>(rarValue );
assertionValue = ClientAssertionBuilder.GetClientAssertion(options.ClientId, options.RsaKey, options.Authority,hcpInfo);
}
else
{
_logger.LogDebug("GetClientAssertionAsync Create ClientAssertion without RAR. No Cookie found");
assertionValue = ClientAssertionBuilder.GetClientAssertion(options.ClientId, options.RsaKey, options.Authority,null);
}
return Task.FromResult<ClientAssertion?>(new ClientAssertion
{
Type = OidcConstants.ClientAssertionTypes.JwtBearer,
Value = assertionValue
});
}