I have a project whose login process is performed using Azure AD and Microsoft Graph.
I would appreciate help with the attached bug - this bug only happens when I use the Google Chrome or Microsoft Edge browser, when I use the Mozilla browser I don't get the error and the process works as it should.
ErrorMessage-IDX21323: RequireNonce is 'True'. OpenIdConnectProtocolValidationContext.Nonce was null, OpenIdConnectProtocol.ValidatedIdToken.Payload.Nonce was not null. The nonce cannot be validated. If you don't need to check the nonce, set OpenIdConnectProtocolValidator.RequireNonce to 'false'. Note if a 'nonce' is found it will be evaluated.
using System;
using System.Text;
using System.Threading.Tasks;
using Owin;
using Microsoft.Owin.Security;
using Microsoft.Identity.Client;
using Microsoft.IdentityModel.Tokens;
using Microsoft.Owin.Security.Cookies;
using Microsoft.AspNetCore.WebUtilities;
using Microsoft.Owin.Security.Notifications;
using Microsoft.Owin.Security.OpenIdConnect;
using Microsoft.IdentityModel.Protocols.OpenIdConnect;
// all my private projects using
namespace Website
{
public partial class Startup
{
private static readonly ILoggerProvider logger = IoC.Resolve<ILoggerProvider>();
private static readonly AzureADSettings azureADSettings = IoC.Resolve<AzureADSettingsFactory>().GetAzureADSettings();
private static readonly string redirectURI = IoC.Resolve<IConfigParameterFactory>().Build("/SSO/AzureAD/RedirectURL", String.Empty).Value;
private static readonly string graphScopes = IoC.Resolve<IConfigParameterFactory>().Build("/AzureAD/GraphScopes", "User.Read.All").Value;
public void ConfigureAuth(IAppBuilder app)
{
string authority = $"https://login.microsoftonline.com/{azureADSettings.TenantID}/v2.0";
string scope = $"openid email profile offline_access {graphScopes}";
string responseType = OpenIdConnectResponseType.CodeIdToken;
TokenValidationParameters tokenValidationParameters = new TokenValidationParameters { ValidateIssuer = true };
OpenIdConnectAuthenticationNotifications notifications = new OpenIdConnectAuthenticationNotifications
{
AuthenticationFailed = OnAuthenticationFailedAsync,
AuthorizationCodeReceived = OnAuthorizationCodeReceivedAsync
};
app.SetDefaultSignInAsAuthenticationType(CookieAuthenticationDefaults.AuthenticationType);
app.UseCookieAuthentication(new CookieAuthenticationOptions());
app.UseOpenIdConnectAuthentication(new OpenIdConnectAuthenticationOptions
{
ClientId = azureADSettings.AppID,
ClientSecret = azureADSettings.AppSecret,
RedirectUri = redirectURI,
Authority = authority,
Scope = scope,
ResponseType = responseType,
TokenValidationParameters = tokenValidationParameters,
Notifications = notifications
});
}
private static Task OnAuthenticationFailedAsync(AuthenticationFailedNotification<OpenIdConnectMessage, OpenIdConnectAuthenticationOptions> notification)
{
notification.HandleResponse();
string errorMessage = $"message-{notification.Exception.Message}";
if (notification.ProtocolMessage != null && !string.IsNullOrEmpty(notification.ProtocolMessage.ErrorDescription))
{
errorMessage += $"--debug-{notification.ProtocolMessage.ErrorDescription}";
}
string errorCode = UserLoginFailed(errorMessage);
string redirectURL = $"{LandingPageEndpoints.ssoErrorPage}?{LandingPageEndpoints.loginErrorUrlPropertyName}={errorCode}";
notification.Response.Redirect(redirectURL);
return Task.FromResult(0);
}
private async Task OnAuthorizationCodeReceivedAsync(AuthorizationCodeReceivedNotification notification)
{
notification.HandleCodeRedemption();
IConfidentialClientApplication idClient =
ConfidentialClientApplicationBuilder.Create(azureADSettings.AppID)
.WithTenantId(azureADSettings.TenantID)
.WithRedirectUri(redirectURI)
.WithClientSecret(azureADSettings.AppSecret)
.Build();
string redirectURL = String.Empty;
try
{
string[] scopes = graphScopes.Split(' ');
AuthenticationResult result = await idClient.AcquireTokenByAuthorizationCode(scopes, notification.Code).ExecuteAsync();
string userToken = EncodeToken(result.AccessToken);
redirectURL = $"{LandingPageEndpoints.ssoAzureADPage}?{LandingPageEndpoints.userTokenUrlPropertyName}={userToken}";
}
catch (MsalException ex)
{
string errorMessage = $"AcquireTokenByAuthorizationCodeAsync threw an exception - {ex.Message}";
string errorCode = UserLoginFailed(errorMessage);
redirectURL = $"{LandingPageEndpoints.ssoErrorPage}?{LandingPageEndpoints.loginErrorUrlPropertyName}={errorCode}";
}
catch (Microsoft.Graph.ServiceException ex)
{
string errorMessage = $"GetUserDetailsAsync threw an exception - {ex.Message}";
string errorCode = UserLoginFailed(errorMessage);
redirectURL = $"{LandingPageEndpoints.ssoErrorPage}?{LandingPageEndpoints.loginErrorUrlPropertyName}={errorCode}";
}
notification.HandleResponse();
notification.Response.Redirect(redirectURL);
}
private static string EncodeToken(string userToken)
{
// My encoding logic
return encodedUserToken;
}
private static string UserLoginFailed(string errorMessage)
{
// My Logger
return ErrorID;
}
}
}