Download AspNetIdentity quickstart here
Configure Google authentication - I.e. setup Client ID, Client Secret for your google api
Configure Google API for the Identity Server callback
Start MVC Client and IdentityServer. Navigate to http://localhost:5002/Home/Secure and try to log in via Google.
External authentication error occurs.
An unhandled exception occurred while processing the request.
Exception: External authentication error
Host.Quickstart.Account.ExternalController.Callback() in ExternalController.cs, line 96
Host.Quickstart.Account.ExternalController.Callback() in ExternalController.cs
var (user, provider, providerUserId, claims) = await FindUserFromExternalProviderAsync(result);
The issue is occurring in ExternalController.cs in the Callback action. The first line tries to Authenticate using a scheme as below:
var result = await HttpContext.AuthenticateAsync(IdentityConstants.ExternalScheme);
Whereas the quickstart sets up the scheme in the actual MVC client as:
options.SignInScheme = IdentityServerConstants.ExternalCookieAuthenticationScheme;
This causes the cookie to not be found and causes the result of the authentication to fail. If I replace var result = await HttpContext.AuthenticateAsync(IdentityConstants.ExternalScheme); with var result = await HttpContext.AuthenticateAsync("idsrv.external"); the exception does not occur.
The quickstart docs does not mention this (http://docs.identityserver.io/en/latest/quickstarts/4_external_authentication.html) issue. Is there a reason why its setup this way?
Where in that quickstart is IdentityConstants.ExternalScheme being used?
Where in that quickstart is
IdentityConstants.ExternalSchemebeing used?
In ExternalController class (https://github.com/IdentityServer/IdentityServer4.Samples/blob/master/Quickstarts/8_AspNetIdentity/src/IdentityServerAspNetIdentity/Quickstart/Account/ExternalController.cs), if you look at the Callback action, the first line of code:
// read external identity from the temporary cookie
var result = await HttpContext.AuthenticateAsync(IdentityConstants.ExternalScheme);
That's QS 8, not QS 4 as you indicated in your initial issue.
Sorry I was referring to the AspNetIdentity quickstart (which is quickstart #8). I also linked to the correct quickstart in my initial issue outline. I was wondering why the scheme was changed for quickstart #8 as the sample does not work for me out of the box (i.e. only filling in Google auth setup).
I just got a clean copy from github on the dev branch and re-ran QS8, filled in my google client/secret, ran it and logged in from google no problem. So I don't know what's wrong in your copy.
I'll close for now. If you find a bug, let us know.
Hi @vrao1020 and @brockallen
We had the same issue.
We integrated multiple Azure AD's and ADFS. The same callback function in ExternalController couldn't cater for the different responses from the different products.
Whilst the default code worked for Azure AD, we had to make a slight modification for ADFS
Our startup for Azure AD is:
services.AddAuthentication()
.AddOpenIdConnect("Name", "Description", options =>
{
options.Authority = "Authority";
options.TokenValidationParameters = new TokenValidationParameters
{
ValidateIssuer = "ValidateIssuer"
};
options.ClientId = "ClientId";
options.CallbackPath = "CallbackPath";
options.SaveTokens = SaveTokens;
options.ResponseType = "ResponseType";
options.GetClaimsFromUserInfoEndpoint = "GetClaimsFromUserInfoEndpoint";
options.ClientSecret = "ClientSecret";
options.SignedOutCallbackPath = "SignedOutCallbackPath";
})
Our start up for ADFS is:
.AddOpenIdConnect("Name", "Description", options =>
{
options.Authority = "Authority";
options.TokenValidationParameters = new TokenValidationParameters
{
NameClaimType = "name",
RoleClaimType = "role"
};
options.ClientId = "ClientId";
options.CallbackPath = "CallbackPath";
options.SignedOutCallbackPath = "SignedOutCallbackPath";
options.SaveTokens = SaveTokens;
options.ResponseType = "ResponseType";
options.SignInScheme = IdentityServerConstants.ExternalCookieAuthenticationScheme;
options.SignOutScheme = IdentityServerConstants.SignoutScheme;
});
Even though the following line was set in the ADFS config, the callback doesn't dynamically check for the different SignInScheme
options.SignInScheme = IdentityServerConstants.ExternalCookieAuthenticationScheme;
The fix was the following in the ExternalController.Callback()
Change
var result = await HttpContext.AuthenticateAsync(IdentityConstants.ExternalScheme);
to
AuthenticateResult result = null;
if (HttpContext.Request.Cookies.Keys.Contains(IdentityServerConstants.ExternalCookieAuthenticationScheme))
result = await HttpContext.AuthenticateAsync(IdentityServerConstants.ExternalCookieAuthenticationScheme);
else
result = await HttpContext.AuthenticateAsync(IdentityConstants.ExternalScheme);
and
await HttpContext.SignOutAsync(IdentityConstants.ExternalScheme);
to
if (HttpContext.Request.Cookies.Keys.Contains(IdentityServerConstants.ExternalCookieAuthenticationScheme))
await HttpContext.SignOutAsync(IdentityServerConstants.ExternalCookieAuthenticationScheme);
else
await HttpContext.SignOutAsync(IdentityConstants.ExternalScheme);
Since ADFS uses the IdentityServerConstants.ExternalCookieAuthenticationScheme the callback needs to validate the response with that scheme.
This thread has been automatically locked since there has not been any recent activity after it was closed. Please open a new issue for related bugs.
Most helpful comment
Hi @vrao1020 and @brockallen
We had the same issue.
We integrated multiple Azure AD's and ADFS. The same callback function in ExternalController couldn't cater for the different responses from the different products.
Whilst the default code worked for Azure AD, we had to make a slight modification for ADFS
Our startup for Azure AD is:
Our start up for ADFS is:
Even though the following line was set in the ADFS config, the callback doesn't dynamically check for the different SignInScheme
The fix was the following in the ExternalController.Callback()
Change
to
and
to
Since ADFS uses the IdentityServerConstants.ExternalCookieAuthenticationScheme the callback needs to validate the response with that scheme.