JWT Token Authentication - Claims not retrieved from token?

Hi

I have followed the docs to add authenticated message queue calls by implementing IHasBearerToken. This works for the authentication. However, I am trying to access session details using
var session = base.SessionAs<CustomUserSession>();
and apart from the basic authentication claims like userName etc, none of the other claims have been decoded from the JWT token.

Stepping through the code, and putting a breakpoint at:
public override void PopulateFromClaims(IRequest httpReq, ClaimsPrincipal principal)

I’ve noted this breakpoint is never hit i.e. the session is not populated from the other claims. Is there a way to enable this? If not, I can decode the token and do it manually, but I suspect I’ve just misconfigured something!

Thanks!

JWTs is limited to only contain Essential Information by default. You can add more information to the JWT with CreatePayloadFilter and populate it to the session with PopulateSessionFilter, e.g:

new JwtAuthProvider(AppSettings) 
{
    CreatePayloadFilter = (payload,session) => 
        payload["CreatedAt"] = session.CreatedAt.ToUnixTime().ToString(),

    PopulateSessionFilter = (session,payload,req) => 
        session.CreatedAt = long.Parse(payload["CreatedAt"]).FromUnixTime()
}

Thanks for the quick response.

Apologies, I should have clarified, I am using ASP.NET Identity. The JWT token is being created by a 3rd party server (Kinde). My client is passing it in the DTO as suggested, and the authentication part works.

There are extra claims in the token, like org_code (I have confirmed that by examining the Request) but they are not being populated in to the session i.e. my CustomUserSession is not being created.

It is easy enough for me to decode the token and grab the claims when I need them, but kind of thought that would be done automatically by servicestack?

I have confirmed that in OnTokenValidated in AddJwtBearer populates the ClaimsPrincipal correctly from the token.

However, in my service, the session returned from base.SessionAs<CustomUserSession>() has none of those extra claims, and base.Request.GetPrincipal() is null as well.

Are these claims on the ASP .NET Principal?

Can use IRequest.GetClaimsPrincipal() to access HttpContext.User:

var claimsPrincipal = req.GetClaimsPrincipal();

That returns null as well

Then it’s not being populated on the Authenticated Identity Auth User Principal which is what populates ServiceStack Auth Session, you’ll need it populated on the CliamsPrincipal first, then you can populate it on the ServiceStack Session by implementing PopulateFromClaims:

Yup, doing all that, and registering the CustomSesion as well:

new AuthFeature(IdentityAuth.For<KindeUser>(options => {
        options.SessionFactory = () => new CustomUserSession();
        options.ApplicationAuth();
        options.JwtAuth();
    })   
)

And to clarify, I am only having an issue with authenticated message queue calls when I pass the JwtBearerToken as a parameter in a DTO with IHasBearerToken. Some of the claims are correctly populated from the session like UserId - just none of the Custom stuff from the token - the method PopulateFromClaims in CustomUserSession is never hit.

Using the JSON client from my react app, everything is populating as expected.

The latest v8.2.3 that’s now in Pre Release Packages should use the same Identity ApplicationAuth provider to populate the session that HTTP Requests use.

Which should let you populate existing AuthUserSession properties with MapClaimsToSession dictionary, e.g:

options.ApplicationAuth(c => {
    c.MapClaimsToSession[JwtClaimTypes.Picture] = 
        nameof(AuthUserSession.ProfileUrl);
});

Otherwise PopulateFromClaims() should now be called to populate the session with custom claims

options.ApplicationAuth(); is enabled by default so not needed unless you’re configuring it

Thanks. I’ve updated to 8.2.3 and found that PopulateFromClaims is still not hit in the one scenario of an authenticated MQ message with IHasBearerToken.

I can populate the session by creating an overload of PopulateFromClaims that just takes a claims list, then populating it when the session is created:

options.JwtAuth(c =>
{
    c.OnSessionCreated = (session, list, request) =>
    {
        var customSession = (CustomUserSession)session;
        customSession.PopulateFromClaims(list);
    };
});

It has pointed me in a slightly different direction, and I am not sure if this is by design or not:

  • When I call a service from a client using the JSON service client with the bearer token in the request Authorization headers, then it uses identity JWT bearer authentication (and my event handlers that populate the claims).
  • When I call a service from the MQ using IHasBearerToken DTOs, the ASP.NET Identity middleware is not used at all, and in IdentityJwtAuthProvider.CreateUserSession(IRequest req, List<Claim> claims), the OriginalRequest is not available and the ClaimsPrincipal is null.

It seems suboptimal for it to bypass the Identity system and also means I have to set up the token validation options etc. twice from what I can see (once to set up Identity and once for ServiceStack Auth).

I am not familiar enough with the inner workings of ServiceStack to investigate any further, but it certainly seems to handle those two scenarios (bearer token in headers vs in DTO) quite differently. Is there somewhere in the source I could be looking?

Thanks ++ for all your help so far.

Right the Identity Middleware for a HTTP Request is not used, it’s a new Request on a new Endpoint where it has to recreate the Session from the token which it does at:

I’m surprised you’re saying PopulateFromClaims() is not being called since it uses AuthApplication to populate the Session at:

Which it then calls PopulateFromClaims at:

Are you sure you’re running the latest v8.2.3? Does your Session inherit the normal AuthUserSession base class?

Sigh, for some reason it seemed to still be using 8.2.2 despite all the packages being updated. It is working once I’ve cleaned and rebuilt.

Thanks for your help - that all works and makes more sense to me as well!

1 Like