IDX21323 from B2C to app

Jim Davidson 0 Reputation points
2023-07-11T17:24:08.5366667+00:00

I have retrofitted a WebForms app with AAD B2C authentication. This has been in production for about 3.5 weeks. Some users have reported that on Sign-in they are prompted for mfa twice (they must send the verification code and verify twice) which didn't occur in test. After investigating the issue, I discovered that error IDX21323 is being thrown on redirect from B2C to the app in these instances. The following code is recovering from the error, but it is redirecting to B2C and subsequently triggering the second mfa verification. I'm looking for a way to prevent the error from occurring in the first place or to prevent the second mfa verification.

If notification.Exception.Message.Contains("IDX21323") Then
                notification.OwinContext.Authentication.Challenge()
                Return Task.FromResult(True)
End If

The full error is: 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.

Here is the startup.auth code:

Partial Public Class Startup
    'App config settings
    Private Shared ReadOnly clientId As String = ConfigurationManager.AppSettings("ida:ClientId")
    Private Shared ReadOnly aadInstance As String = ConfigurationManager.AppSettings("ida:AadInstance")
    Private Shared ReadOnly tenant As String = ConfigurationManager.AppSettings("ida:Tenant")
    Public Shared ReadOnly userProfileSignUpRedirectUri As String = ConfigurationManager.AppSettings("ida:UserProfileSignUpRedirectUri")
    Public Shared ReadOnly vendorSignUpRedirectUri As String = ConfigurationManager.AppSettings("ida:VendorSignUpRedirectUri")
    Public Shared ReadOnly signInRedirectUri As String = ConfigurationManager.AppSettings("ida:SignInRedirectUri")
    Public Shared ReadOnly profileEditRedirectUri As String = ConfigurationManager.AppSettings("ida:ProfileEditRedirectUri")
    Private Shared ReadOnly postLogoutRedirectUri As String = ConfigurationManager.AppSettings("ida:PostLogoutRedirectUri")
    'B2C policy identifiers
    Public Shared UserProfileSignUpPolicyId As String = ConfigurationManager.AppSettings("ida:UserProfileSignUpPolicyId")
    Public Shared VendorSignUpPolicyId As String = ConfigurationManager.AppSettings("ida:VendorSignUpPolicyId")
    Public Shared SignInPolicyId As String = ConfigurationManager.AppSettings("ida:SignInPolicyId")
    Public Shared ProfileEditPolicyId As String = ConfigurationManager.AppSettings("ida:ProfileEditPolicyId")
    'Public Shared emailValue As String
    Public Sub ConfigureAuth(app As IAppBuilder)
        Try
            app.SetDefaultSignInAsAuthenticationType(CookieAuthenticationDefaults.AuthenticationType)
            app.UseCookieAuthentication(New CookieAuthenticationOptions() With {
                .CookieSameSite = SameSiteMode.None,
                .CookieSecure = CookieSecureOption.Always
            })
            'Configure OpenID Connect middleware for each policy
            app.UseOpenIdConnectAuthentication(CreateOptionsFromPolicy(UserProfileSignUpPolicyId, userProfileSignUpRedirectUri, userProfileSignUpRedirectUri))
            app.UseOpenIdConnectAuthentication(CreateOptionsFromPolicy(VendorSignUpPolicyId, vendorSignUpRedirectUri, vendorSignUpRedirectUri))
            app.UseOpenIdConnectAuthentication(CreateOptionsFromPolicy(ProfileEditPolicyId, profileEditRedirectUri, profileEditRedirectUri))
            app.UseOpenIdConnectAuthentication(CreateOptionsFromPolicy(SignInPolicyId, signInRedirectUri, postLogoutRedirectUri))
        Catch ex As Exception
            'WriteErrorToLog(ex.ToString, HttpContext.Current.Session("LoggedInUser"), "B2C Configure Auth", Reflection.MethodBase.GetCurrentMethod().Name)
            LogMessage(Me.ToString(), System.Reflection.MethodBase.GetCurrentMethod().Name, "Exception", ex.ToString())
            'HttpContext.Current.Response.Redirect($"../errAppError.aspx")
        End Try
    End Sub
    Private Function AuthenticationFailed(notification As AuthenticationFailedNotification(Of OpenIdConnectMessage, OpenIdConnectAuthenticationOptions)) As Task
        Dim emailAddress As String = ""
        Try
            Dim authenticationProperties As AuthenticationProperties = notification?.OwinContext?.Authentication?.AuthenticationResponseChallenge?.Properties
            If authenticationProperties IsNot Nothing AndAlso authenticationProperties.Dictionary.ContainsKey("useremail") Then
                emailAddress = authenticationProperties.Dictionary("useremail")
            End If
            If notification Is Nothing Then
                LogMessage(Me.ToString(), System.Reflection.MethodBase.GetCurrentMethod().Name, "Informational", "Email: '" + emailAddress + "': MS Owin.Security returned an error, but the notification argument is null.")
                Return Task.FromResult(0)
            End If
            LogMessage(Me.ToString(), System.Reflection.MethodBase.GetCurrentMethod().Name, "Informational", "Email: '" + emailAddress + "': B2C AuthenticationFailed: " + notification.Exception.ToString())
            notification.HandleResponse()
            If notification.Exception.Message.Contains("IDX21323") Then
                notification.OwinContext.Authentication.Challenge()
                Return Task.FromResult(True)
            End If
            If notification.Exception.Message.Contains("AADB2C90091") Then
                If notification.Options.AuthenticationType.Contains("ProfileEdit") Then
                    notification.Response.Redirect($"../UserProfile.aspx")
                Else
                    notification.Response.Redirect($"../NoAccess.aspx?MSG=9&MsgContent=Authentication Error: Signup/Signin Aborted")
                End If
            Else
                HttpContext.Current.GetOwinContext().Authentication.SignOut(CookieAuthenticationDefaults.AuthenticationType)
                HttpContext.Current.Session("LoginErrors") = "Authentication Error: SignUp/SignIn could not be completed. Please close the browser before trying again."
                notification.Response.Redirect($"../NoAccess.aspx?MSG=9&MsgContent=Authentication Error: SignUp/SignIn could not be completed. Please close the browser before trying again.")
            End If
        Catch ex As Exception
            LogMessage(Me.ToString(), System.Reflection.MethodBase.GetCurrentMethod().Name, "Exception", "Email: '" + emailAddress + "': " + ex.ToString())
            notification.Response.Redirect($"../NoAccess.aspx?MSG=9&MsgContent=Authentication Error: SignUp/SignIn could not be completed. Please close the browser before trying again.")
        End Try
        Return Task.FromResult(0)
    End Function
    Private Function CreateOptionsFromPolicy(policy As String, redirectUri As String, logoutUri As String) As OpenIdConnectAuthenticationOptions
        ' For each policy, give OWIN the policy-specific metadata address, And
        ' set the authentication type to the id of the policy
        'These are standard OpenID Connect parameters, with values pulled from web.config
        Dim options As New OpenIdConnectAuthenticationOptions With {
            .MetadataAddress = String.Format(aadInstance, tenant, policy),
            .AuthenticationType = policy,
            .ClientId = clientId,
            .RedirectUri = redirectUri,
            .PostLogoutRedirectUri = logoutUri,
            .Notifications = New OpenIdConnectAuthenticationNotifications With {
                .AuthenticationFailed = AddressOf AuthenticationFailed,
                .RedirectToIdentityProvider = Function(notification)
                                                  Dim authenticationProperties As AuthenticationProperties = notification?.OwinContext?.Authentication?.AuthenticationResponseChallenge?.Properties
                                                  If authenticationProperties IsNot Nothing AndAlso authenticationProperties.Dictionary.ContainsKey("useremail") Then
                                                      Dim additionalParamValue As String = authenticationProperties.Dictionary("useremail")
                                                      'Create an instance of AuthenticationProperties and add the additional parameter
                                                      If Not String.IsNullOrEmpty(additionalParamValue) Then
                                                          notification.ProtocolMessage.Parameters.Add("signInName", additionalParamValue)
                                                      End If
                                                  End If
                                                  Return Task.FromResult(0)
                                              End Function
             },
            .Scope = OpenIdConnectScope.OpenId,
            .ResponseType = OpenIdConnectResponseType.IdToken,
            .TokenValidationParameters = New TokenValidationParameters With {
                .NameClaimType = "name"
            },
            .CookieManager = New SameSiteCookieManager(New SystemWebCookieManager())
        }
        Return options
    End Function
End Class
Microsoft Entra ID
Microsoft Entra ID
A Microsoft Entra identity service that provides identity management and access control capabilities. Replaces Azure Active Directory.
20,630 questions
{count} votes