4

Following the official IdentityServer4 documentation, I reached the point where I have an MVC client app, IdentityServer4 and a Web Api (resource server running). IS4 homepage displays all claims for the user, and when calling the api with the access token, we again get as a result all the user's claims.

Sample code is available here, although it's probably not necessary, and I'm just missing something obvious.

Anyway, for simplicity's sake let's not get claims from the DB and just assign a random hardcoded one:

public class ProfileService : IProfileService
{
    public Task GetProfileDataAsync(ProfileDataRequestContext context)
    {
        context.IssuedClaims.Add(new System.Security.Claims.Claim("role", "admin"));
        return Task.FromResult(0);
    }
    ...
}

I register the custom Profile service in the startup file and now when I'm logged in on IS4, I see the additional claim.

However, when calling the web api (resource server), this additional claim is not included in the JWT. Code for api call:

    public async Task<IActionResult> CallApiUsingUserAccessToken()
    {
        var accessToken = await HttpContext.Authentication.GetTokenAsync("access_token");

        var client = new HttpClient();
        client.SetBearerToken(accessToken);
        var content = await client.GetStringAsync("http://localhost:5001/identity");

        ViewBag.Json = JArray.Parse(content).ToString();
        return View("json");
    }

(All the api does is return the list of User.Claims). My added claim is not in there, and when I debug the code and pick the access token string and decode it on jwt.io, there's no such claim again.

Question is : what am I missing? is the HttpContext.Authentication.GetTokenAsync bad for my use case, and if so - what is the substitute I'm supposed to use?

Edit: Here are the OpenId Connect Options (on the MVC client):

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

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

            ClientId = "mvc",
            ClientSecret = "secret",

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

            GetClaimsFromUserInfoEndpoint = true,
            SaveTokens = true
        });
nikovn
  • 1,900
  • 5
  • 22
  • 28
  • 1
    Please provide `OpenIdConnectOptions`, if you are using – Vikas Sardana Jan 15 '17 at 19:04
  • I am not sure I understand correctly but just because you add a new claim at the server side in a web method, it doesn't mean you reissue the token to actually contain this new claim. Try anything else like removing all claims, the effect should be the same. Unless you issue a new token, changes to the identity you make at the server are temporary and last only during such specific requests. Something like deleting a cookie from the cookies collection at the server but not sending a new set-cookie to actually delete it at the client. – Wiktor Zychla Jan 15 '17 at 20:28

1 Answers1

3

I guess the reason is that you haven't assigned any claims to your API. This is why we don't call the profile service at all.

This is a common problem and a little inconsistent since we are always calling the profile service for identity tokens.

We changed this behavior in 1.0.2

https://github.com/IdentityServer/IdentityServer4/releases/tag/1.0.2

Please try again and see if this gives you the expected result.

leastprivilege
  • 18,196
  • 1
  • 34
  • 50
  • It does, thank you so much! I guess it was never a bug, but the new IS4 version saves a lot of headache, as most aspects of openId connect are really not intuitive. – nikovn Jan 16 '17 at 10:46
  • 2
    How to add email and username claims, when they are not added explicitly in the AspNetUserClaims? – ravi punjwani Jan 17 '17 at 01:01
  • @leastprivilege To clarify, are you saying that with this modification the claims set by IProfileService are now _always_ added to both the Identity Token _and_ the Access Token? And that the old behaviour was just to append them to the Identity Token? This appears to be what I'm seeing, moving from 1.0.0 to 1.1.1. – mikebridge Feb 18 '17 at 21:46
  • From reading [the code](https://github.com/IdentityServer/IdentityServer4/blob/f5b5d2e28e1251cea51183bacb23e54102c50dd4/src/IdentityServer4/Services/DefaultClaimsService.cs#L83) for that commit, it looks like the `IProfileService` is indeed queried for each token type. – mikebridge Feb 23 '17 at 22:06