Search code examples
c#asp.net-coreasp.net-identityopenid-connectidentityserver4

Adding custom Claim for access in API with IdentityServer4


I'm trying to work with a application to use IdentityServer4, it has the basic setup of the identity server, MVC client, and web API.

I have a custom Profile service (which I've registered in Startup.cs) where I'm adding a custom claim, here's my GetProfileDataAsync method:

public Task GetProfileDataAsync(ProfileDataRequestContext context)
{
    var user = _userManager.GetUserAsync(context.Subject).Result;

    var claims = new List<Claim>
    {
        new Claim("TestFullName", user.FullName),
    };

    context.IssuedClaims.AddRange(claims);          

    return Task.FromResult(0);
}

My problem is that when I log into the identity server, I can see the additional claim - but when I call my API from the MVC app, my custom claim isn't there. Here's the code in my MVC app to call the API:

public async Task<IActionResult> ClientAuthorizedAPICall(string token)
{
    // discover endpoints from metadata
    var disco = await DiscoveryClient.GetAsync("http://localhost:5000");

    // request token
    var tokenClient = new TokenClient(disco.TokenEndpoint, "client", "secret");
    var tokenResponse = await tokenClient.RequestClientCredentialsAsync("testAPI");        

    // call api
    var client = new HttpClient();
    client.SetBearerToken(tokenResponse.AccessToken);

    var response = await client.GetAsync("http://localhost:5001/identity");
    ...
} 

And the method on my API is simply:

[HttpGet]
public IActionResult Get()
{
    return new JsonResult(from c in User.Claims select new { c.Type, c.Value });           
}

Am I doing something wrong? Or should I be doing something different instead of using User.Claims?


Solution

  • Like rawel's comment says, you'll want to use the MVC app user's access token to make your API call. It would look something like this:

    // get the current user's access token
    var accessToken = await HttpContext.GetTokenAsync("access_token");
    
    // call api
    var client = new HttpClient();
    client.SetBearerToken(accessToken);
    
    var response = await client.GetAsync("http://localhost:5001/identity");
    

    You can see a similar approach in the quickstart on hybrid flow.

    To get your custom user claim into the access token for your API, you'll need to include it when defining the API resource. For example:

    new ApiResource("testAPI", "Test API", new[] { "TestFullName" }),