Identityserver4: External OIDC provider get claims

Created on 23 Apr 2020  路  5Comments  路  Source: IdentityServer/IdentityServer4

Question

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:

  1. {s_hash: WzuL1SHu8q5pvPBP0fG9MQ}
  2. {sid: f0DB9kMIA-27rGg3CRToMw}
  3. {http://schemas.xmlsoap.org/ws/2005/05/identity/claims/nameidentifier: 1}
  4. {http://schemas.microsoft.com/identity/claims/identityprovider: local}
  5. {http://schemas.microsoft.com/claims/authnmethodsreferences: pwd}

How can I get additional claims from the external provider such as profile, email? I already requested these scopes during login.

Minimal working example

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();

Relevant parts of the log file

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
question wontfix

All 5 comments

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.

Was this page helpful?
0 / 5 - 0 ratings

Related issues

user1336 picture user1336  路  3Comments

agilenut picture agilenut  路  3Comments

leastprivilege picture leastprivilege  路  3Comments

osmankibar picture osmankibar  路  3Comments

krgm03 picture krgm03  路  3Comments