IdentityServer4 RequestedClaimTypes is Empty

2.5k views Asked by At

In my profile service why is RequestedClaimTypes Empty? I am expecting the profile claims to be requested. And per this they should contain FamilyName and Given Name claim types.

GetIdentityResources

public static IEnumerable<IdentityResource> GetIdentityResources()
{
    return new List<IdentityResource>
    {
        new IdentityResources.OpenId(),
        new IdentityResources.Profile(),
    };
}

Client

new Client
{
    ClientId = "46a0ab4a-1321-4d77-abe5-98f09310df0b",
    ClientName = "TypeScript SPA client",
    RequireClientSecret = false, // if false this is a public client.
    AllowedGrantTypes = GrantTypes.Implicit,
    AllowAccessTokensViaBrowser = true,

    RedirectUris = { "http://localhost:3000/callback" },
    PostLogoutRedirectUris = { "http://localhost:3000/" },
    AllowedCorsOrigins = { "http://localhost:3000" },

    AllowedScopes =
    {
        IdentityServerConstants.StandardScopes.OpenId,
        IdentityServerConstants.StandardScopes.Profile,
    },

    RequireConsent = false,
},

oidc-client configuration typescript

const myOidcClientSettings: OidcClientSettings = {
  authority: `${protocol}//${hostname}:5000`,
  client_id: '46a0ab4a-1321-4d77-abe5-98f09310df0b',
  post_logout_redirect_uri: `${protocol}//${hostname}${port ? `:${port}` : ''}/`,
  redirect_uri: `${protocol}//${hostname}${port ? `:${port}` : ''}/callback`,
  response_type: 'id_token token',
  scope: 'openid profile'
};

const myUserManagerSettings: UserManagerSettings = {
  ...myOidcClientSettings,
  automaticSilentRenew: false,
  filterProtocolClaims: true,
  loadUserInfo: true,
  monitorSession: false,
  silent_redirect_uri: `${protocol}//${hostname}${port ? `:${port}` : ''}/callback`,
};

Inside the Login Post I add the following claims:

Claim[] claims =
{
  new Claim(JwtClaimTypes.Name, $"{loginResponse.FirstName} {loginResponse.LastName}"),
  new Claim(JwtClaimTypes.Email, loginResponse.EmailAddress),
  new Claim(JwtClaimTypes.PhoneNumber, loginResponse.PhoneNumber),
  new Claim(JwtClaimTypes.FamilyName, loginResponse.LastName),
  new Claim(JwtClaimTypes.GivenName, loginResponse.FirstName),
  //new Claim(JwtClaimTypes.AuthorizationCodeHash, aRequest.Password), // The Password will be need by the BFF but can NOT be sent to the Typescript client
};

await HttpContext.Authentication.SignInAsync(subjectId, userName, authenticationProperties, claims);

ProfileService

    public Task GetProfileDataAsync(ProfileDataRequestContext aProfileDataRequestContext)
{
  Logger.LogDebug("Get profile called for {subject} from {client} with {claimTypes} because {caller}",
      aProfileDataRequestContext.Subject.GetSubjectId(),
      aProfileDataRequestContext.Client.ClientName,
      aProfileDataRequestContext.RequestedClaimTypes,
      aProfileDataRequestContext.Caller);

  if (aProfileDataRequestContext.RequestedClaimTypes.Any())
  {
    aProfileDataRequestContext.AddFilteredClaims(aProfileDataRequestContext.Subject.Claims);
  }

  return Task.FromResult(0);
}

Resulting User Info that profile does NOT contain the profile items: (Shortend for readability

"User info": {
  "id_token": "eyJhbGciOiJSUzI1N",
  "session_state": "M5uV9nYzvmlWjvpjmX--OOPcwAEeVesV7aG9ZO0svS8.8f757e9a033183149734adb156fbb39d",
  "access_token": "eyJhbGciOiJSUzI1NiIsImtpZCI6",
  "token_type": "Bearer",
  "scope": "openid profile",
  "profile": {
    "sid": "4372a4cbb9938449a39d72db1a9fc6f0",
    "sub": "[email protected]",
    "auth_time": 1505037917,
    "idp": "local",
    "amr": [
      "pwd"
    ]
  },
  "expires_at": 1505042091,
  "state": {
    "returnUrl": "/en-us/test"
  }
}
1

There are 1 answers

2
Ganesh Kumar Ponnuswamy On BEST ANSWER

It looks like you have to include the following option to your client,

AlwaysIncludeUserClaimsInIdToken = true

So that your client will include the claims in the token.