0
votes

I have implemented an IdentityServer4 solution using asp.net core with ASP.Net Identity. SO far so good. I have configured the solution such that user claims are NOT transmitted with the access token and the client must invoke the UserInfo endpoint to get the user claims. The problem I am having is that the website (client) calls a public api which then calls a private api in which I need to access the user claims. From the private api I make a call to the user info endpoint requesting the user claims and recieve everything. I was expecting to recieve only the claims defined by the APiResource (openid only) but instead I receive all user claims as requested by the client (openid, profile, email, address etc). I presumed the profile service would be able to understand that the apiresource requested userinfo - not the client and thus reduce the claims returned but that didn't happen. My question is this. How do I make my ProfileService aware of the originator of a call such that if the private api calls UserINfo itv returns only those claims defined in the ApiResource?

I am using reference tokens so my client looks as follows (not all properties included)

new Client
{
    ClientId = "client",
    AccessTokenType = AccessTokenType.Reference,
    ClientSecrets = { new Secret("secret".Sha256()) },
    AllowedScopes = { "openid", "profile", "email" }
}

I have defined two api resources as follows:

new ApiResource("public_api"){
    Scopes = new List<string> { "openid" }
}
new ApiResource("private_api"){
    Scopes = new List<string> { "openid" },
}

My client (website) requests the following scopes:

openid, profile, email

Using the above configuration, when checking User.Claims at each level I see the following values:

  • WEBSITE can see user claims: name, family_name, given_name and email
  • PUBLIC API has no user claims information
  • PRIVATE API has no user claims information

Following the suggestion by Tore Nestenius I changed the private api resource as follows:

new ApiResource("private_api"){
    Scopes = new List<string> { "openid" },
    UserClaims = { "email", "email_verified" }
}

Re-running the application, I now see the following values:

  • WEBSITE can see user claims: name, family_name, given_name and email (no change thought not sure why email_verified is not shown?)
  • PUBLIC API can see user claims: email and email_verified
  • PRIVATE API can see user claims: email and email_verified

What I don't understand is why does the public api see the email user claims? I was expecting that ONLY the private api would see those claims but that doesn't appear to be the case. Ideally I'd like to restrict each micro-service to only see the user claims that are defined against the Api Resource. I hope this helps clarify what's going on.

1

1 Answers

1
votes

UserInfoEndpoint alaways returns the users claims.

To just get the ApiResources userclaims, you need to ask the TokenIntrospection endpoint. The purpose of this endpoint is for API's defined as ApiResources to query the IdentityServer for userclaims. Also for checking if an access token is still valid.

You must also map which of the user claims should be present in the token introspection result, using code like:

new ApiResource()
{
    Name = "paymentapi",

    Scopes = new List<string> { "payment"},

    ApiSecrets = new List<Secret>() { new Secret("myapisecret".Sha256()) },

    UserClaims = new List<string>
    {
        "creditlimit", "paymentaccess","admin"
    }

}

Also, if this flag is set, all the user claims are also included in the access token:

    /// <summary>
    /// Gets or sets a value indicating whether client claims should be always included in the access tokens - or only for client credentials flow.
    /// Defaults to <c>false</c>
    /// </summary>
    /// <value>
    /// <c>true</c> if claims should always be sent; otherwise, <c>false</c>.
    /// </value>
    public bool AlwaysSendClientClaims { get; set; } = false;