Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Fix IDX21323: RequireNonce is 'False' during token refreshClient #240

Merged
merged 3 commits into from
Mar 9, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
14 changes: 7 additions & 7 deletions 8.0/BlazorWebAppOidc/BlazorWebAppOidc/CookieOidcRefresher.cs
Original file line number Diff line number Diff line change
Expand Up @@ -12,12 +12,12 @@
namespace BlazorWebAppOidc;

// https://github.com/dotnet/aspnetcore/issues/8175
internal sealed class CookieOidcRefresher(IOptionsMonitor<OpenIdConnectOptions> oidcOptionsMonitor) : IDisposable
internal sealed class CookieOidcRefresher(IOptionsMonitor<OpenIdConnectOptions> oidcOptionsMonitor)
{
private readonly HttpClient refreshClient = new();
private readonly OpenIdConnectProtocolValidator oidcTokenValidator = new()
{
// Refresh requests do not use the nonce parameter. Otherwise, we'd use oidcOptions.ProtocolValidator.
// We no longer have the original nonce cookie which is deleted at the end of the authorization code flow having served its purpose.
// Even if we had the nonce, it's likely expired. It's not intended for refresh requests. Otherwise, we'd use oidcOptions.ProtocolValidator.
RequireNonce = false,
};

Expand All @@ -39,7 +39,7 @@ public async Task ValidateOrRefreshCookieAsync(CookieValidatePrincipalContext va
var oidcConfiguration = await oidcOptions.ConfigurationManager!.GetConfigurationAsync(validateContext.HttpContext.RequestAborted);
var tokenEndpoint = oidcConfiguration.TokenEndpoint ?? throw new InvalidOperationException("Cannot refresh cookie. TokenEndpoint missing!");

using var refreshResponse = await refreshClient.PostAsync(tokenEndpoint,
using var refreshResponse = await oidcOptions.Backchannel.PostAsync(tokenEndpoint,
new FormUrlEncodedContent(new Dictionary<string, string?>()
{
["grant_type"] = "refresh_token",
Expand Down Expand Up @@ -77,11 +77,13 @@ public async Task ValidateOrRefreshCookieAsync(CookieValidatePrincipalContext va
return;
}

var validatedIdToken = JwtSecurityTokenConverter.Convert(validationResult.SecurityToken as JsonWebToken);
validatedIdToken.Payload["nonce"] = null;
oidcTokenValidator.ValidateTokenResponse(new()
{
ProtocolMessage = message,
ClientId = oidcOptions.ClientId,
ValidatedIdToken = JwtSecurityTokenConverter.Convert(validationResult.SecurityToken as JsonWebToken),
ValidatedIdToken = validatedIdToken,
});

validateContext.ShouldRenew = true;
Expand All @@ -97,6 +99,4 @@ public async Task ValidateOrRefreshCookieAsync(CookieValidatePrincipalContext va
new() { Name = "expires_at", Value = expiresAt.ToString("o", CultureInfo.InvariantCulture) },
]);
}

public void Dispose() => refreshClient.Dispose();
}
14 changes: 7 additions & 7 deletions 8.0/BlazorWebAppOidcBff/BlazorWebAppOidc/CookieOidcRefresher.cs
Original file line number Diff line number Diff line change
Expand Up @@ -12,12 +12,12 @@
namespace BlazorWebAppOidc;

// https://github.com/dotnet/aspnetcore/issues/8175
internal sealed class CookieOidcRefresher(IOptionsMonitor<OpenIdConnectOptions> oidcOptionsMonitor) : IDisposable
internal sealed class CookieOidcRefresher(IOptionsMonitor<OpenIdConnectOptions> oidcOptionsMonitor)
{
private readonly HttpClient refreshClient = new();
private readonly OpenIdConnectProtocolValidator oidcTokenValidator = new()
{
// Refresh requests do not use the nonce parameter. Otherwise, we'd use oidcOptions.ProtocolValidator.
// We no longer have the original nonce cookie which is deleted at the end of the authorization code flow having served its purpose.
// Even if we had the nonce, it's likely expired. It's not intended for refresh requests. Otherwise, we'd use oidcOptions.ProtocolValidator.
RequireNonce = false,
};

Expand All @@ -39,7 +39,7 @@ public async Task ValidateOrRefreshCookieAsync(CookieValidatePrincipalContext va
var oidcConfiguration = await oidcOptions.ConfigurationManager!.GetConfigurationAsync(validateContext.HttpContext.RequestAborted);
var tokenEndpoint = oidcConfiguration.TokenEndpoint ?? throw new InvalidOperationException("Cannot refresh cookie. TokenEndpoint missing!");

using var refreshResponse = await refreshClient.PostAsync(tokenEndpoint,
using var refreshResponse = await oidcOptions.Backchannel.PostAsync(tokenEndpoint,
new FormUrlEncodedContent(new Dictionary<string, string?>()
{
["grant_type"] = "refresh_token",
Expand Down Expand Up @@ -77,11 +77,13 @@ public async Task ValidateOrRefreshCookieAsync(CookieValidatePrincipalContext va
return;
}

var validatedIdToken = JwtSecurityTokenConverter.Convert(validationResult.SecurityToken as JsonWebToken);
validatedIdToken.Payload["nonce"] = null;
oidcTokenValidator.ValidateTokenResponse(new()
{
ProtocolMessage = message,
ClientId = oidcOptions.ClientId,
ValidatedIdToken = JwtSecurityTokenConverter.Convert(validationResult.SecurityToken as JsonWebToken),
ValidatedIdToken = validatedIdToken,
});

validateContext.ShouldRenew = true;
Expand All @@ -97,6 +99,4 @@ public async Task ValidateOrRefreshCookieAsync(CookieValidatePrincipalContext va
new() { Name = "expires_at", Value = expiresAt.ToString("o", CultureInfo.InvariantCulture) },
]);
}

public void Dispose() => refreshClient.Dispose();
}
Loading