26
votes

I getting this error when a Azure AD user login (I able to get the user´s claims after), im using a combination of OpenIdConnect, with asp.net Identity core over net.core 2.0

An unhandled exception occurred while processing the request. Exception: Correlation failed. Microsoft.AspNetCore.Authentication.RemoteAuthenticationHandler+d__12.MoveNext()

The trace:

Exception: Correlation failed. Microsoft.AspNetCore.Authentication.RemoteAuthenticationHandler+d__12.MoveNext() System.Runtime.ExceptionServices.ExceptionDispatchInfo.Throw() System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task) System.Runtime.CompilerServices.TaskAwaiter.GetResult() Microsoft.AspNetCore.Authentication.AuthenticationMiddleware+d__6.MoveNext() System.Runtime.ExceptionServices.ExceptionDispatchInfo.Throw() System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task) Microsoft.AspNetCore.Diagnostics.DeveloperExceptionPageMiddleware+d__7.MoveNext()

Correlation Failed

Here is my Startup.cs:

using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
using BPT.PC.IdentityServer.Data;
using BPT.PC.IdentityServer.IdentityStore;
using BPT.PC.IdentityServer.Models;
using Microsoft.AspNetCore.Authentication;
using Microsoft.AspNetCore.Authentication.Cookies;
using Microsoft.AspNetCore.Authentication.OpenIdConnect;
using Microsoft.AspNetCore.Builder;
using Microsoft.AspNetCore.Hosting;
using Microsoft.AspNetCore.Identity;
using Microsoft.EntityFrameworkCore;
using Microsoft.Extensions.Configuration;
using Microsoft.Extensions.DependencyInjection;

namespace BPT.PC.IdentityServer.Web
{
    public class Startup
    {
        public Startup(IConfiguration configuration)
        {
            Configuration = configuration;
        }

        public IConfiguration Configuration { get; }

        // This method gets called by the runtime. Use this method to add services to the container.
        public void ConfigureServices(IServiceCollection services)
        {
            services.AddIdentity<User, Role>()
                .AddUserStore<UserStore>()
                .AddRoleStore<RoleStore>()
                .AddDefaultTokenProviders();

            services.AddMemoryCache();
            services.AddDistributedMemoryCache();
            services.AddDbContext<IdentityServerDb>(options => options.UseSqlServer(Configuration.GetConnectionString("IdentityServerDb")));

            services.AddMvc();
            services.AddAuthentication(auth =>
            {
                auth.DefaultAuthenticateScheme = CookieAuthenticationDefaults.AuthenticationScheme;
                auth.DefaultChallengeScheme = CookieAuthenticationDefaults.AuthenticationScheme;
                auth.DefaultSignInScheme = CookieAuthenticationDefaults.AuthenticationScheme;
            })
            .AddCookie()
            .AddOpenIdConnect("AzureAD", opts =>
            {
                Configuration.GetSection("OpenIdConnect").Bind(opts);
                opts.RemoteAuthenticationTimeout = TimeSpan.FromSeconds(120);
                opts.SignInScheme = CookieAuthenticationDefaults.AuthenticationScheme;

                opts.CorrelationCookie = new Microsoft.AspNetCore.Http.CookieBuilder
                {
                    HttpOnly = false,
                    SameSite = Microsoft.AspNetCore.Http.SameSiteMode.None,
                    SecurePolicy = Microsoft.AspNetCore.Http.CookieSecurePolicy.None,
                    Expiration = TimeSpan.FromMinutes(10)
                };

                opts.Events = new OpenIdConnectEvents()
                {
                    OnRedirectToIdentityProvider = OnRedirectToIdentityProvider,
                    OnRemoteFailure = OnRemoteFailure,
                    OnAuthorizationCodeReceived = OnAuthorizationCodeReceived
                };
                //opts.Events = new OpenIdConnectEvents
                //{
                //    OnAuthorizationCodeReceived = ctx =>
                //    {
                //        return Task.CompletedTask;
                //    }
                //};
            });

            //services.ConfigureApplicationCookie(options =>
            //{
            //    // Cookie settings
            //    options.Cookie.HttpOnly = true;
            //    options.ExpireTimeSpan = TimeSpan.FromMinutes(30);
            //    options.SlidingExpiration = true;
            //});
        }

        private Task OnAuthorizationCodeReceived(AuthorizationCodeReceivedContext arg)
        {
            return Task.FromResult(0);
        }

        private Task OnRemoteFailure(RemoteFailureContext arg)
        {
            return Task.FromResult(0);
        }

        private Task OnRedirectToIdentityProvider(RedirectContext arg)
        {
            return Task.FromResult(0);
        }

        // This method gets called by the runtime. Use this method to configure the HTTP request pipeline.
        public void Configure(IApplicationBuilder app, IHostingEnvironment env)
        {
            if (env.IsDevelopment())
            {
                app.UseBrowserLink();
                app.UseDeveloperExceptionPage();
            }
            else
            {
                app.UseExceptionHandler("/Home/Error");
            }

            app.UseStaticFiles();
            app.UseAuthentication();

            app.UseMvc(routes =>
            {
                routes.MapRoute(
                    name: "default",
                    template: "{controller=Account}/{action=Login}/{id?}");
            });
        }
    }
}

My appsettings.json:

{
  "Logging": {
    "IncludeScopes": false,
    "LogLevel": {
      "Default": "Warning"
    }
  },

  "ConnectionStrings": {
    "IdentityServerDb": "Server=localhost;Database=IdentityServer;Trusted_Connection=True;MultipleActiveResultSets=true"
  },

  "OpenIdConnect": {
    "ClientId": "xxxxx",
    "Authority": "https://login.microsoftonline.com/xxxxx/",
    "PostLogoutRedirectUri": "/Account/SignoutOidc",
    "CallbackPath": "/Account/SigninOidc",
    "UseTokenLifetime": true,
    "RequireHttpsMetadata": false,
    //"ResponseType": "code id_token",
    "ClientSecret": "xxx",
    "Resource": "https://graph.microsoft.com/"
  }
}

And the implementation:

[HttpGet]
public IActionResult CorpLogin()
{
  var authProperties = _signInManager
                .ConfigureExternalAuthenticationProperties("AzureAD",
     Url.Action("SigninOidc", "Account", null, Request.Scheme));

   return Challenge(authProperties, "AzureAD");
}

[HttpPost]
public IActionResult SigninOidc([FromForm]object data)
{
//this never runs
   return Ok();
}
12
Um... Is there some proxy or firewall on your machine?Wayne Yang
Maybe, but I could fixed the problem excluding asp.net identiy, do you know if there is any known issue at that?Augusto Diaz
The error description is very unhelpful to people unfamiliar with OIDC internals: I want to know exactly what "correlation failed" means - what X is trying to correlate what Y with what Z?Dai
@Wayne in my case there is a proxy, any hint how to make that work even with proxy in place?Samuel

12 Answers

68
votes

If you're using Chrome against localhost, you may have run into a change in Chrome cookie-handling behaviour.

To verify, navigate to chrome://flags/ and change "Cookies without SameSite must be secure" to "Disabled".

If that change fixes the issue, and you want to fix it permanently (i.e. not rely on the chrome flags fix), this thinktecture post talks about the underlying issue and some fixes that you'll need for old iOS safari versions.

14
votes

I've finally found the solution, I´ll post here just in case somebody have a similar problem.

Looks like the principal problem was that my redirect URI was the same that the CallBackPath:

"CallbackPath": "/Account/SigninOidc"

var authProperties = _signInManager .ConfigureExternalAuthenticationProperties("AzureAD", Url.Action("SigninOidc", "Account", null, Request.Scheme));

Well, here is my corrected Startup.cs:

using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
using BPT.PC.IdentityServer.Data;
using BPT.PC.IdentityServer.IdentityStore;
using BPT.PC.IdentityServer.Models;
using BPT.PC.IdentityServer.Web.Models;
using Microsoft.AspNetCore.Authentication;
using Microsoft.AspNetCore.Authentication.Cookies;
using Microsoft.AspNetCore.Authentication.OpenIdConnect;
using Microsoft.AspNetCore.Builder;
using Microsoft.AspNetCore.Hosting;
using Microsoft.AspNetCore.Http;
using Microsoft.AspNetCore.Identity;
using Microsoft.EntityFrameworkCore;
using Microsoft.Extensions.Configuration;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.IdentityModel.Protocols.OpenIdConnect;

namespace BPT.PC.IdentityServer.Web
{
    public class Startup
    {
        public Startup(IConfiguration configuration)
        {
            Configuration = configuration;
        }

        public IConfiguration Configuration { get; }

        // This method gets called by the runtime. Use this method to add services to the container.
        public void ConfigureServices(IServiceCollection services)
        {
            services.AddIdentity<User, Role>()
                .AddUserStore<UserStore>()
                .AddRoleStore<RoleStore>()
                .AddDefaultTokenProviders();

            services.AddMemoryCache();
            services.AddDistributedMemoryCache();
            services.AddDbContext<IdentityServerDb>
                (options => options.UseSqlServer(Configuration.GetConnectionString("IdentityServerDb")));

            services
                .AddMvc();
            services
                .AddAuthentication(auth =>
                {
                    auth.DefaultAuthenticateScheme = CookieAuthenticationDefaults.AuthenticationScheme;
                    auth.DefaultChallengeScheme = CookieAuthenticationDefaults.AuthenticationScheme;
                    auth.DefaultSignInScheme = CookieAuthenticationDefaults.AuthenticationScheme;
                })
                .AddCookie()
                .AddOpenIdConnect("AzureAD", "AzureAD", options =>
                {
                    Configuration.GetSection("AzureAD").Bind(options); ;
                    options.ResponseType = OpenIdConnectResponseType.CodeIdToken;
                    options.RemoteAuthenticationTimeout = TimeSpan.FromSeconds(120);
                    options.SignInScheme = CookieAuthenticationDefaults.AuthenticationScheme;
                    options.RequireHttpsMetadata = false;
                    options.SaveTokens = true;
                });

            services.AddSingleton(Configuration.GetSection("OpenIdConnectProviderConfiguration").Get<OpenIdConnectProviderConfiguration>());

        }
        // This method gets called by the runtime. Use this method to configure the HTTP request pipeline.
        public void Configure(IApplicationBuilder app, IHostingEnvironment env)
        {
            if (env.IsDevelopment())
            {
                app.UseBrowserLink();
                app.UseDeveloperExceptionPage();
            }
            else
            {
                app.UseExceptionHandler("/Home/Error");
            }

            app.UseStaticFiles();
            app.UseAuthentication();

            app.UseMvc(routes =>
            {
                routes.MapRoute(
                    name: "default",
                    template: "{controller=Account}/{action=Login}/{id?}");
            });
        }
    }
}

And the finally implementation:

[HttpGet]
public IActionResult CorpLogin()
    {
        var authProperties = _signInManager
            .ConfigureExternalAuthenticationProperties("AzureAD",
            Url.Action("LoggingIn", "Account", null, Request.Scheme));

        return Challenge(authProperties, "AzureAD");
    }

The appsettings.json is the same.

9
votes

I was hitting this issue when using login with Google using .net Identity in Blazor on chrome. I had a new requirement to get it to work without https, it had been working fine with https.

I read in multiple answers variants of changing to

app.UseCookiePolicy(new CookiePolicyOptions()
{
    MinimumSameSitePolicy = SameSiteMode.None
});

I wish I'd read @dbruning's answer's article sooner. It mentioned in the article which isn't mentioned anywhere else: Please note: The setting SameSite=None will only work if the cookie is also marked as Secure and requires a HTTPS connection. The method's intellisense summary doesn't mention this which I think it definitely should...

So after that I just tried using SameSiteMode.Lax instead and it worked for me again. No other changes required from the default blazor project startup.cs

app.UseCookiePolicy(new CookiePolicyOptions()
{
    MinimumSameSitePolicy = SameSiteMode.Lax
});
7
votes

Just FYI: I met same issue which cost me almost 1 day to investigate on this issue. finally I found that after remove below code from my startup.cs and everything is working: CookiePolicyOptions cookiePolicy = new CookiePolicyOptions() { Secure = CookieSecurePolicy.Always, };

I am following up this with Microsoft support team, will update this back if get got any response.

5
votes

The problem for me was that the clock on my machine (I am using a virtual machine) was not set to the correct time. It was behind by a few days because I had paused the VM after last using it.

So the solution was to simply adjust the clock to be the correct time.

3
votes

This Happens when you try to access the URL which is assigned as 'Callback Path' in your OIDC settings.

To resolve this change your Callback Path to something like, 'MyController/MyAction' which will redirect you to your specific URL , in your case '/Account/SigninOidc'.

3
votes

In my case, I had to go to Visual Studio menus,

Project=> Application Properties => Debug tab = Enable SSL true

And in the actual OAuth configuration in FB Developer's account, set use https. This has resolved. There may be different complicated problems for others. In my case this has sorted it.

2
votes

Thanks to Tim.Tang's answer, I figured out what caused the error on my end on Core 2.2. It was similar except that the error appeared when I removed the code for cookie policy in Startup.cs > ConfigureServices method:

services.Configure<CookiePolicyOptions>(options =>
{
    // This lambda determines whether user consent for non-essential cookies is needed for a given request.
    options.CheckConsentNeeded = context => true;
    options.MinimumSameSitePolicy = SameSiteMode.None;
});

This was because I forgot to also remove app.UseCookiePolicy(); code in the Configure method.

2
votes

I was having a very similar issue and none of the answers posted in this whole thread worked for me. I will describe how I reached the solution, in case it can help anybody else.

In my case, I have a web app with ASP.NET Core 3.1 (migrated from 1.x) and implemented authentication with the following snippet in the ConfigureServices method, from Startup.cs (as described here):

services.AddAuthentication(OpenIdConnectDefaults.AuthenticationScheme)
    .AddMicrosoftIdentityWebApp(Configuration.GetSection("AzureAd"));

The error thrown, as can be seen here, had a much simpler stack trace that the one described on this thread.

In the end, the problem was that cookies were not being set as secure. To do so, I just added the following code snippet right before the services.AddAuthentication pasted above.

services.Configure<CookiePolicyOptions>(options =>
{
    options.Secure = CookieSecurePolicy.Always;
});

Furthermore, I added a call to app.UseCookiePolicy() right before the call to app.UseRouting() in the Configure() method in Startup.cs.

0
votes

This issue is mostly happening when you are running identity server on http and browser is chrome , try running the application on IE Edge or use https always should fix the issue

0
votes

I had the exact same problem

Exception: Correlation failed.

while trying to authenticate my dotNet Core 3 app to AzureAD.

Changing my launch profile to "Project" and adding a https App URL ("https://localhost:5001;http://localhost:5000") actually did the trick for me!

0
votes

Put this at the top of Startup.Configure(), before other middleware Uses:

app.UseCookiePolicy(new CookiePolicyOptions
{
    MinimumSameSitePolicy = SameSiteMode.Strict
});

Tested using IdentityServer 4.1.2, .NET Core 5