User Impersonation - Is session used or JWT?

We have nearly everything working for user impersonation (we’ve switched to using JWT primarily, we can generate tokens on the fly and refresh them, we have a short lived bearer with a long-lived refresh, we parse all of our primary data out of the bearerToken). I’ve studied and better understand how ServiceStacks auth works, but one thing alludes me: how does servicestack determine if it uses the cached session info vs the JWT?

When we swap JWTs to impersonate, some endpoints are using the JWT’s data, and some endpoints seem to use the old Session data (the Admin user instead of my Impersonated user). Sometimes the PopulateSessionFilter wasn’t hit, or the SessionAs() still returns the old data. As an example, some of my AutoQuery endpoints (list screens) return the impersonated users data, and the POST endpoints are creating as the non-impersonated user.

Is there anything else I need to do with the Session? Or with settings we use on the javascript client? Maybe it’s the long-running server events client connection holding on to the session?

The FromToken property on the Session indicates if the session was created by a JWT or from a cached UserSession.

You shouldn’t be using both, when you switch to use JWT like if you’re using the built-in ConvertSessionToToken it will automatically remove the server session, if you’re doing the JWT switch yourself you’ll want to remove the server session with IRequest.RemoveSession().

Ahhh ok, so we’ll want to clear the current users session (as well as maybe change our server events clients to subscribe via a JWT as stated in the Send JWTs in the HTTP Params documentation). That would make us fully JWT dependent.

I’d personally use JWT Cookies that way it’s sent automatically as a Cookie and you don’t have to handle manually populating the JWT on each request.

But you can’t use Cookies in node server apps or javascript integration tests and would need to pass the JWT in the QueryString.

But wouldn’t that mess up once we try to impersonate? IE the Token Cookie would be set on login (authenticate), but after we call our Admin restricted GetBearerTokenEndpoint for impersonation, the token cookie is still being sent instead of the new JWT we just got.

You could just replace the ss-tok Cookie, e.g. here’s how JWT Auth Provider returns the ss-tok Cookie:

return new HttpResult(response)
{
    Cookies = {
        new Cookie(Keywords.TokenCookie, token, Cookies.RootPath) {
            HttpOnly = true,
            Secure = Request.IsSecureConnection,
            Expires = DateTime.UtcNow.Add(jwtAuthProvider.ExpireTokensIn),
        }
    }
};

Ohhhh, where would I do this? In my custom GetBearerToken endpoint?

Then I wouldn’t have to mess with initializing the server events client with JWT Params, nor would I have to use my custom setToken(bearer, refresh) on our client.js upon JWT change?

You can do this in any service, I’d expect you’d be returning this in the service that impersonates the user.

Right, Cookies are automatically set by clients/browsers/etc and resent on subsequent requests.

The only problem would be the call to stop impersonating as they wouldn’t have the required role (Admin) since the ss-tok is the impersonated user.

Is there a way to tell the JsonServiceClient to explicitly use a given JWT over ss-tok? Then I could maintain the admins JWT and pass it back in.

The ss-tok cookie is used last, the IRequest.GetJwtToken() extension method shows the resolution order of JWT’s:

Implementation of IRequest.GetBearerToken():

How does using the Token Cookie work with refresh tokens? I’ve changed around my implementation some to utilize ss-tok, but noticed that when I get a Token has expired or Invalid token response, the automatic refresh doesn’t occur (it just logs me out). When switching to this method, does it not use the auto-refresh?

Are you using the TypeScript or the C# JsonServiceClient?

The RefreshToken still needs to be populated on the client in order to be able to fetch a new Bearer Token, but it only populates the bearerToken property on the client.

It looks like you may be able to implement a onAuthenticationRequired callback to either set a client cookie locally (in browser) or in the C# client you can use SetTokenCookie(), the alternative way to configure the cookie on the client is to make a request to ConvertSessionToToken.

I’ve finished adding support for using TokenCookies in Refresh Tokens in the C# GetAccessToken server and C# JsonServiceClient, JsonHttpClient and TypeScript JsonServiceClient.

You’ll need to upgrade to the latest v5.5.1 on MyGet to use it on the server and latest v1.0.23 of @servicestack/client in npm.

Then if you configure your client with:

client.useTokenCookie = true;

It will request that the new bearerToken returned in refresh token’s GetAccessToken response be returned via the ss-tok cookie, overriding any existing one.

Great, will the bearerToken also be returned in the response for parsing?

No, one of the primary benefits of the token cookie is that it’s HTTP only and any malicious JavaScript script running on your page wont be able to access it.

Actually that won’t matter, this is all an automated process. The only time I need to re-parse the JWT is when impersonating or updating a users roles.

Thanks for the update!

1 Like

Just curious, when the auto-refresh GetAccessToken is used to do a behind the scenes refresh, does it useTokenCookie?

Nevermind, I see the code. It’s dependent on if your client uses .useTokenCookie