I am currently working on a large ASP.NET MVC application with authentication against Azure Active Directory. This uses the OpenID Connect protocol to login using your AD username and password.

Looking through our ELMAH error logs, I noticed quite a few of the following exception:

Microsoft.IdentityModel.Protocols.OpenIdConnectProtocolInvalidNonceException

IDX10316: The 'nonce' has expired: '...'. Time from 'nonce': '19/01/2017 13:09:13', Current Time: '19/01/2017 15:48:05'. NonceLifetime is: '01:00:00'  

Since every page in the web application requires authentication, the user will always be greeted with the Azure AD login screen. It turns out that if the user leaves the login page open for more than one hour and then attempts to login, it will fail with the above exception. The user has to close the tab and open the site again.

There doesn't appear to be a fix from Microsoft for this issue yet, so we will just have to work around it.

The easiest thing to do is just increase time expiration time of the nonce from the default 1 hour to something longer such as 24 hours. This doesn't resolve the issue, but makes it far less likely to occur in real life applications.

To do this, in your Startup.Auth.cs file, set the NonceLifetime to your desired TimeSpan:

public void ConfigureAuth(IAppBuilder app)  
{
    ...
    app.UseOpenIdConnectAuthentication(
        new OpenIdConnectAuthenticationOptions
        {
            ...
            // Set expiration time to 6 hours
            ProtocolValidator = new OpenIdConnectProtocolValidator() { NonceLifetime = new TimeSpan(0,6,0,0)},
            ...
        });
}

Since this isn't really fixing it, we can also write some code to handle the exception when it occurs and force a reload of the site and hence generate a new nonce.

Again, in Startup.Auth.cs

public void ConfigureAuth(IAppBuilder app)  
{
    ...
    app.UseOpenIdConnectAuthentication(
        new OpenIdConnectAuthenticationOptions
        {
                ...
                AuthenticationFailed = (context) =>
                {
                    ...
                    if (context.Exception is OpenIdConnectProtocolInvalidNonceException && context.Exception.Message.Contains("IDX10316"))
                    {
                        Trace.WriteLine("Nonce expired, reauthenticating...");
                        context.HandleResponse();
                        // Redirect to the originally requested URL
                        context.Response.Redirect(context.Request.Uri.PathAndQuery);
                    }
                    return Task.FromResult(0);
                }
                ...
            }
        );
}

This will check if the authentication failed due to the Nonce expiration and force a refresh to ensure a new nonce is generated.

References