2

I'm developing a set of applications including an Identity Server using IdentityServer4, a .NET Core MVC app, a .NET Core WebAPI.

As part of a asp.net core mvc application I am using AddOpenIdConnect to do authentication and doing options.SaveTokens = true.

However, as part of Claims Transformation, in TransformAsync I would like to be able to have access to the access token provided by the identityserver. This is to be able to call a permissions endpoint on the api to populate the principal with claims that I can use to do authorization on my controllers etc.

If I call HttpContext.GetTokenAsync("access_token") I get a stackoverflowexception due to the infinite loop created by authenticate being called, which then calls TransformAsync again.

Is this a sound approach in the first place? Typically, TransformAsync is where I would populate application permissions. Is there any way of accessing the token without triggering the authenticate again?

Would appreciate any help as we're a bit stumped! Thanks

Edit: I've seen suggestions around doing transformations in the OnTicketReceived event. It looks like I'd have access to the token through the properties in there. Is this a better place to do it?

Dom
  • 77
  • 1
  • 7
  • I suggest you look at the creating the ProfileService and adding it to pipeline very little extra work and it will pull and put the claims information into the JWT token for you. Not sure if that is what you are looking for. I too was alittle a stumped at first but that little extra bit helped implementing IProfileService which is in IS4 already. then I just drop in `UserManager` with DI and grab `IUserClaimsPrincipalFactory` as well to pull in User information from Context. – mvermef Dec 23 '17 at 06:16
  • Thanks for your reply but I'm not sure that this is what we are looking for. The profile service appears to be just for adding extra claims - still related to identity itself - that have not been populated in the initial cookie. What we are looking for is the application claims to be populated from an API to the Client when our user makes a request. Thanks. – Dom Jan 08 '18 at 07:51
  • Yes, OnTicketReceived or many of the other OIDC events would work for this. – Tratcher Jan 09 '18 at 04:26

3 Answers3

2

I came across the same problem. My solution was,

Override JwtBearerEvents.TokenValidated event called by IdentityServer4.AccessTokenValidation middleware.

private Task OnTokenValidated(TokenValidatedContext tokenValidatedContext)
    {
        tokenValidatedContext.HttpContext.Items["access_token"] = (tokenValidatedContext.SecurityToken as JwtSecurityToken).RawData;
        return Task.CompletedTask;
    }

This will utilize HttpContext.Items collection which is request scoped. Now you can retreive this access token in TransformAsync method, like below.

var access_token = _httpContextAccessor.HttpContext.Items["access_token"] as string;

Please note that you need to inject IHttpContextAccessor to access HttpContext in ClaimsTransformer.

tha4
  • 390
  • 1
  • 9
1

It has been many years since this question was posted, but if you are still looking for a solution to the issue, you can get the access token in the OnTokenValidated event.

OnTokenValidated = tokenValidatedContext =>
{
    var handler = new JwtSecurityTokenHandler();
    // get access token
    var jsonToken = handler.ReadJwtToken(tokenValidatedContext.TokenEndpointResponse.AccessToken); 

    var claims = new List<Claim>();

    claims.Add(new Claim("customClaimType", "customClaimValue"));

    var appIdentity = new ClaimsIdentity(claims);

    tokenValidatedContext.Principal.AddIdentity(appIdentity);
    return Task.CompletedTask;

}

Reference : Adding Custom Claims During Authentication

Vivek Sharma
  • 1,912
  • 1
  • 13
  • 15
0

I think you can inject the IAuthenticationHandlerProvider service and use following:

  1. Get the authentication handler by scheme name.
  2. get the AuthenticateResult by invoking AuthenticateAsync
  3. get the token from the authentication properties

    var token = string.Empty;
    var handler = await Handlers.GetHandlerAsync(context, scheme); // i.e. "OIDC"
    var result = await handler.AuthenticateAsync();
    if(result?.Succeeded == true) {
        token = result?.Properties?.GetTokenValue(tokenName);
    }
    

haven't tested it but i think it should work

Almogo
  • 81
  • 2
  • 3
  • Thanks for your reply. Unfortunately this method causes the same problem as my original post. `AuthenticateAsync` triggers `TransformAsync` so we get stuck in an infinite loop. – Dom Jan 12 '18 at 09:14