Identityserver4: How to get additional User Info in Claims?

Created on 16 Feb 2017  路  4Comments  路  Source: IdentityServer/IdentityServer4

I am using IdentityServer4 with AspNetCoreIdentity. I extend my ApplicationUser class and want to access its few properties after user logged in, I trying to get additional user properties by userinfo endpoint, but it always return two claims, sub and name. I also inject custom profile service implementing IProfileService and add it in startup services pipeline, but it never invoked. What I missed, here are my config and client startup settings:

config.cs in IdentityServer:

public class Config
{
    // scopes define the resources in your system
    public static IEnumerable<IdentityResource> GetIdentityResources()
    {
        return new List<IdentityResource>
        {
            new IdentityResources.OpenId(),
            new IdentityResources.Profile(),
            new IdentityResources.Email()
        };
    }

    public static IEnumerable<ApiResource> GetApiResources()
    {
        return new List<ApiResource>
        {
            new ApiResource("API4", "My API")
        };
    }

    // clients want to access resources (aka scopes)
    public static IEnumerable<Client> GetClients()
    {
        // client credentials client
        return new List<Client>
        {
            // OpenID Connect hybrid flow and client credentials client (MVC)
            new Client
            {
                ClientId = "WebApp",
                ClientName = "MVC Client",
                AllowedGrantTypes = GrantTypes.HybridAndClientCredentials,

                RequireConsent = false,

                ClientSecrets = 
                {
                    new Secret("secret".Sha256())
                },

                RedirectUris = { "http://localhost:8875/signin-oidc" },
                PostLogoutRedirectUris = { "http://localhost:8875" },

                AllowedScopes =
                {
                    IdentityServerConstants.StandardScopes.OpenId,
                    IdentityServerConstants.StandardScopes.Profile,
                    IdentityServerConstants.StandardScopes.Email,
                    "API4"
                },

                AllowOfflineAccess = true

            }
        };
    }
}

startup.cs in IdentityServer:

  services.AddTransient<IProfileService, CustomProfileService>();

  services.AddIdentityServer()
            .AddTemporarySigningCredential()
            .AddInMemoryPersistedGrants()
            .AddInMemoryIdentityResources(Config.GetIdentityResources())
            .AddInMemoryApiResources(Config.GetApiResources())
            .AddInMemoryClients(Config.GetClients())
            .AddAspNetIdentity<ApplicationUser>();

and startup.cs in Client Application

       app.UseCookieAuthentication(new CookieAuthenticationOptions
        {
            AuthenticationScheme = "Cookies"
        });

        app.UseOpenIdConnectAuthentication(new OpenIdConnectOptions
        {
            AuthenticationScheme = "oidc",
            SignInScheme = "Cookies",

            Authority = "http://localhost:9018",
            RequireHttpsMetadata = false,

            ClientId = "WebApp",
            ClientSecret = "secret",

            ResponseType = "code id_token",
            Scope = { "API4", "offline_access" },                

            GetClaimsFromUserInfoEndpoint = true,
            SaveTokens = true
        });
question

Most helpful comment

@nhdmalik Try moving the call to AddProfileService to the end of the AddIdentityServer chain, like so:

  services.AddIdentityServer()
            .AddTemporarySigningCredential()
            .AddInMemoryPersistedGrants()
            .AddInMemoryIdentityResources(Config.GetIdentityResources())
            .AddInMemoryApiResources(Config.GetApiResources())
            .AddInMemoryClients(Config.GetClients())
            .AddAspNetIdentity<ApplicationUser>()
            .AddProfileService<CustomProfileService>();

The AddAspNetIdentity method registers its own IProfileService, which will overwrite any previous registration.

All 4 comments

@nhdmalik If you want to add your custom implementation for IProfileService you can do it with extension-method called 'AddProfileService'inside ConfigureServices method. It will looks like this

services.AddIdentityServer()
         .AddProfileService<CustomProfileService>()
         .AddSigningCredential(signingCertificate);

But also you need to add some custom claims to your apiresource. And also you need to implement your custom claims creation process in your IProfileService implementation class.

P.S. - sorry for my English. I just want to help)

@NoMoreLoad thanks for your response, I add the profile service as mentioned by you but still its method not invoked, looks like state secret, what I am missing in server config and in client startup to setup as I required?

@nhdmalik Try moving the call to AddProfileService to the end of the AddIdentityServer chain, like so:

  services.AddIdentityServer()
            .AddTemporarySigningCredential()
            .AddInMemoryPersistedGrants()
            .AddInMemoryIdentityResources(Config.GetIdentityResources())
            .AddInMemoryApiResources(Config.GetApiResources())
            .AddInMemoryClients(Config.GetClients())
            .AddAspNetIdentity<ApplicationUser>()
            .AddProfileService<CustomProfileService>();

The AddAspNetIdentity method registers its own IProfileService, which will overwrite any previous registration.

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