I added an external provider, just to test I used https://demo.identityserver.io/. I use the "interactive.public" client which requires pkce. when the external login is successful I authenticate using the ExternalCookieAuthenticationscheme. The request returns 5 claims:
How can I get additional claims from the external provider such as profile, email? I already requested these scopes during login.
External provider configuration
services.AddAuthentication()
.AddOpenIdConnect("oidc","Demo IDP",options =>
{
options.SignInScheme = IdentityServerConstants.ExternalCookieAuthenticationScheme;
options.SignOutScheme = IdentityServerConstants.SignoutScheme;
options.SaveTokens = true;
options.Authority = "https://demo.identityserver.io/";
options.ClientId = "interactive.public";
options.ResponseType = "code";
options.Scope.Add("email");
options.Scope.Add("offline_access");
options.TokenValidationParameters = new TokenValidationParameters
{
NameClaimType = "name",
RoleClaimType = "role"
};
#region enable PKCE
/*
* Used to enable PKCE during the authentication flow.
* In ASP.NET CORE 3 OnRedirectToIdentityProvider and OnAuthorizationCodeReceived can be replaced by: "options.UsePkce = true;"
*/
options.Events.OnRedirectToIdentityProvider = context =>
{
// only modify requests to the authorization endpoint
if (context.ProtocolMessage.RequestType == OpenIdConnectRequestType.Authentication)
{
// generate code_verifier
var codeVerifier = CryptoRandom.CreateUniqueId(32);
// store codeVerifier for later use
context.Properties.Items.Add("code_verifier", codeVerifier);
// create code_challenge
string codeChallenge;
using (var sha256 = SHA256.Create())
{
var challengeBytes = sha256.ComputeHash(Encoding.UTF8.GetBytes(codeVerifier));
codeChallenge = Base64Url.Encode(challengeBytes);
}
// add code_challenge and code_challenge_method to request
context.ProtocolMessage.Parameters.Add("code_challenge", codeChallenge);
context.ProtocolMessage.Parameters.Add("code_challenge_method", "S256");
}
return Task.CompletedTask;
};
options.Events.OnAuthorizationCodeReceived = context =>
{
// only when authorization code is being swapped for tokens
if (context.TokenEndpointRequest?.GrantType == OpenIdConnectGrantTypes.AuthorizationCode)
{
// get stored code_verifier
if (context.Properties.Items.TryGetValue("code_verifier", out var codeVerifier))
{
// add code_verifier to token request
context.TokenEndpointRequest.Parameters.Add("code_verifier", codeVerifier);
}
}
return Task.CompletedTask;
};
#endregion
});
Challange external provider
[HttpGet]
public async Task<IActionResult> Challenge(string provider, string returnUrl)
{
if (string.IsNullOrEmpty(returnUrl)) returnUrl = "~/";
// validate returnUrl - either it is a valid OIDC URL or back to a local page
if (Url.IsLocalUrl(returnUrl) == false && _interaction.IsValidReturnUrl(returnUrl) == false)
{
// user might have clicked on a malicious link - should be logged
throw new Exception("invalid return URL");
}
if (AccountOptions.WindowsAuthenticationSchemeName == provider)
{
// windows authentication needs special handling
return await ProcessWindowsLoginAsync(returnUrl);
}
else
{
// start challenge and roundtrip the return URL and scheme
var props = new AuthenticationProperties
{
RedirectUri = Url.Action(nameof(Callback)),
Items =
{
{ "returnUrl", returnUrl },
{ "scheme", provider },
},
};
return Challenge(props, provider);
}
}
Authenticate With ExternalCookieAuthetnicationScheme
var result = await HttpContext.AuthenticateAsync(IdentityServer4.IdentityServerConstants.ExternalCookieAuthenticationScheme);
var exClaims = result.Principal.Claims.ToList();
Returned Claims:
dbug: IdentityServer4.Quickstart.UI.ExternalController[0]
External claims: s_hash: WzuL1SHu8q5pvPBP0fG9MQ, sid: f0DB9kMIA-27rGg3CRToMw, http://schemas.xmlsoap.org/ws/2005/05/identity/claims/nameidentifier: 1, http://schemas.microsoft.com/identity/claims/identityprovider: local, http://schemas.microsoft.com/claims/authnmethodsreferences: pwd
Oh my gosh, I have been struggling with identical issue all day. How to get email address/display name back from Identity Server.
I have added in IS client
"AllowedScopes": [ "openid", "profile", "api1", "email" ],
Within my client I have added
.AddOpenIdConnect("oidc", options =>
....
options.Scope.Add("api1");
options.Scope.Add("offline_access");
options.Scope.Add("email");
)
Also within IS ExternalController I have added ensuring that the email address is WITHIN additionalLocalClaims collection.
await HttpContext.SignInAsync(user.SubjectId, user.Username, provider, localSignInProps, additionalLocalClaims.ToArray());
Any ideas?
I may have found my solution...
_"Boolean to set whether the handler should go to user info endpoint to retrieve additional claims or not after creating an identity from id_token received from token endpoint. The default is 'false'."_
options.GetClaimsFromUserInfoEndpoint = true;
[https://docs.microsoft.com/en-us/dotnet/api/microsoft.aspnetcore.authentication.openidconnect.openidconnectoptions.getclaimsfromuserinfoendpoint?view=aspnetcore-3.0]
Thank you this solved it for me, I also spend a whole day trying to get those claims.
Another option would've been to manually do a request to the token endpoint, but this solution is way better.
It might be a good idea to put this explicitly in the external provider documentation page:.
This issue has been automatically marked as stale because it has not had recent activity. It will be closed if no further activity occurs.
Questions are community supported only and the authors/maintainers may or may not have time to reply. If you or your company would like commercial support, please see here for more information.
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.