Closed krispenner closed 1 year ago
I suspect that this might be a bug related to sessions obtaining access tokens before any of the dpop support existed, and so not reporting a token type at all (bearer vs dpop). Do you get this error for existing users with existing sessions only? Or do you also get it for new sessions?
It is happening for new sessions both after clearing all cookies and using an Incognito browser. I do have some custom sign-in code that may be affecting it. When we get an access token returned from a backend (BFF) call, we automatically sign-in the user using Cookie authentication. I had to sort of hack this together to make it work, maybe this is now the issue?
internal class SignInAccessTokenTransform : ResponseTransform
{
private readonly ILogger _logger;
public SignInAccessTokenTransform(ILogger<SignInAccessTokenTransform> logger)
{
ArgCheck.NotNull(nameof(logger), logger);
_logger = logger;
}
public override async ValueTask ApplyAsync(ResponseTransformContext context)
{
// Check for an access token returned in the API response.
if (context?.HttpContext == null || context.ProxyResponse?.Headers?.TryGetValues("X-API-AuthorizationToken", out var authorizationToken) != true || authorizationToken?.Count() != 1)
{
return;
}
var accessToken = authorizationToken.LastOrDefault()?.TrimToNull();
if (accessToken == null)
{
return;
}
_logger.LogTrace("Access token found in proxied response: " + accessToken);
// If an access token was found in the API response, validate it.
var principal = context.HttpContext.RequestServices
.GetRequiredService<ITokenValidationService>()
.ValidateToken(accessToken, isIdToken: false, out var validatedToken);
if (principal == null || validatedToken == null)
{
_logger.LogWarning(("An access token was found in the proxied response but it could not be validated. " + principal?.Identity?.Name + " " + validatedToken?.ToString()).CollapseAndTrim());
return;
}
await context.HttpContext.SignInAsync(AuthenticationSchemes.FrontendUserSession, principal, new()
{
AllowRefresh = true,
IsPersistent = false,
IssuedUtc = validatedToken.ValidFrom,
ExpiresUtc = validatedToken.ValidTo,
// TODO: Shouldn't be hacking this in, there must be a proper way to store it.
Items = { { ".Token.access_token", accessToken } }
}).ConfigureAwait(false);
context.HttpContext.Response?.Headers?.Remove("X-API-AuthorizationToken");
}
}
The key line in question is: Items = { { ".Token.access_token", accessToken } }
.
Could this be causing the issue now? Do I need to store this differently? Is there a better built-in mechanism to sign-in a user myself with an access token?
@josephdecock I have now changed my code to the following and it seems to be working again. Maybe you can direct me to a better way to add a token to the authentication properties?
await context.HttpContext.SignInAsync(AuthenticationSchemes.FrontendUserSession, principal, new()
{
AllowRefresh = true,
IsPersistent = false,
IssuedUtc = validatedToken.ValidFrom,
ExpiresUtc = validatedToken.ValidTo,
// TODO: Shouldn't be hacking this in, there must be a cleaner way to store it.
Items =
{
{ $".Token.{OpenIdConnectParameterNames.AccessToken}", accessToken },
{ $".Token.{OpenIdConnectParameterNames.TokenType}", OidcConstants.AuthenticationSchemes.AuthorizationHeaderBearer },
{ $".Token.{OpenIdConnectParameterNames.ExpiresIn}", validatedToken.ValidTo.ToString("o", CultureInfo.InvariantCulture) },
}
}).ConfigureAwait(false);
Under the hood, the BFF manages tokens using the Duende.AccessTokenManagement library. That includes a service which can store tokens for you.
From Duende.AccessTokenManagement.OpenIdConnect, inject a IUserTokenStore, and then call its StoreTokenAsync method.
I'm closing this issue, and we'll track further developments in https://github.com/DuendeSoftware/BFF/issues/182
Which version of Duende BFF are you using? 2.1.1
Which version of .NET are you using? 6.0
Describe the issue
We are a paying customer with a license for BFF. Since we upgraded to your latest version we now get an error with the bearer token in AccessTokenRequestTransform. I'm looking at code changes in GitHub and I see a lot of changes with added support for DPoP and how the token is now passed around (no longer a simple string). However, from digging through my logs and your code I can't see why my requests are failing now.
There were 8 commits between June 8th and 14th that drastically changed how the AccessTokenRequestTransform uses the bearer token.
Just hoping you can tell me anything obvious (configuration maybe) that I may need to change to make my code work again as everything worked prior to this upgrade.