« Back to home

Asp.net Core 2.0 Identity with multiple OIDC providers

I ran into an issue working on an OpenId Connect (OIDC) project recently and it turned out to be due to my usage rather than a bug, however I don't think it was obvious what I was doing wrong.
Once I found out the answer I wanted to use this blog post to record it here in case I run into it again in future and if it helps someone else then that's great too.

I was adding multiple OpenId Connect configurations to a brand new ASP.net Core 2.0 project and depending on which endpoint I clicked on I was seeing a rather unhelpful error message.

The relevant Startup.cs snippet was

            services.AddAuthentication()
                .AddOpenIdConnect("idservoidc1", "OpenID Connect 1", options =>
                {
                    options.Authority = "https://demo.identityserver.io/";
                    options.ClientId = "implicit";
                }).AddOpenIdConnect("idservoidc2", "OpenID Connect 2", options =>
                {
                    options.Authority = "https://demo.identityserver.io/";
                    options.ClientId = "implicit";

                }).AddOpenIdConnect("idservoidc3", "OpenID Connect 3", options =>
                {
                    options.Authority = "https://demo.identityserver.io/";
                    options.ClientId = "implicit";
                });

The error message was not very helpful

System.Exception: Correlation failed.  
   at Microsoft.AspNetCore.Authentication.RemoteAuthenticationHandler`1.<HandleRequestAsync>d__12.MoveNext()
--- End of stack trace from previous location where exception was thrown ---
   at System.Runtime.ExceptionServices.ExceptionDispatchInfo.Throw()
   at System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task)
   at System.Runtime.CompilerServices.TaskAwaiter`1.GetResult()
   at Microsoft.AspNetCore.Authentication.AuthenticationMiddleware.<Invoke>d__6.MoveNext()
--- End of stack trace from previous location where exception was thrown ---
   at System.Runtime.ExceptionServices.ExceptionDispatchInfo.Throw()
   at System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task)
   at Microsoft.AspNetCore.Diagnostics.EntityFrameworkCore.MigrationsEndPointMiddleware.<Invoke>d__4.MoveNext()
--- End of stack trace from previous location where exception was thrown ---
   at System.Runtime.ExceptionServices.ExceptionDispatchInfo.Throw()
   at System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task)
   at Microsoft.AspNetCore.Diagnostics.EntityFrameworkCore.DatabaseErrorPageMiddleware.<Invoke>d__6.MoveNext()
--- End of stack trace from previous location where exception was thrown ---
   at System.Runtime.ExceptionServices.ExceptionDispatchInfo.Throw()
   at Microsoft.AspNetCore.Diagnostics.EntityFrameworkCore.DatabaseErrorPageMiddleware.<Invoke>d__6.MoveNext()
--- End of stack trace from previous location where exception was thrown ---
   at System.Runtime.ExceptionServices.ExceptionDispatchInfo.Throw()
   at System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task)
   at Microsoft.AspNetCore.Diagnostics.DeveloperExceptionPageMiddleware.<Invoke>d__7.MoveNext()

After a lot of searching I didn't find anything useful so decided to post an issue on the ASP.net security Github repo as the error was originating from the OpenId Connect middleware.

Thankfully someone from the team responded very quickly and put me straight, the issue was being caused by not having a unique callback path for each endpoint.

By default if you don't specify the callback path it defaults to /oidc-signin which is fine if you only have one endpoint specified but when you add multiple endpoints you need to ensure each endpoint has a unique callback path. Therefore the solution was to add a unique callbackpath to each endpoint and everything worked fine.

            services.AddAuthentication()
                .AddOpenIdConnect("idservoidc1", "OpenID Connect 1", options =>
                {
                    options.Authority = "https://demo.identityserver.io/";
                    options.ClientId = "implicit";
                    options.CallbackPath = "/oidc1-signin";

                }).AddOpenIdConnect("idservoidc2", "OpenID Connect 2", options =>
                {
                    options.Authority = "https://demo.identityserver.io/";
                    options.ClientId = "implicit";
                    options.CallbackPath = "/oidc2-signin";

                }).AddOpenIdConnect("idservoidc3", "OpenID Connect 3", options =>
                {
                    options.Authority = "https://demo.identityserver.io/";
                    options.ClientId = "implicit";
                    options.CallbackPath = "/oidc3-signin";
                });

I'm sure this in the documentation but I didn't find it, the error message wasn't helpful at all and only occurred if you clicked on the second or third endpoints only.
Hopefully this helps someone and I would like to contribute back to the middleware to improve the error message when I get a chance.