Chaining Authentication / Session Management

I have a two tier setup and I am looking to implement full authentication / session management with the following structure:

  • Service A is an ASP MVC web application
  • Service B is a typical service stack rest API service.

I have been reading about the way to implement a custom auth provider in Service B so that I can control access to the API calls.

Additionally I have read that I can initialize the client connection from A to B using the following approach

var client = new JsonServiceClient(BaseUrl);

var authResponse = client.Post(new Authenticate {
    provider = CredentialsAuthProvider.Name, //= credentials
    UserName = "test@gmail.com",
    Password = "p@55w0rd",
    RememberMe = true,
});

Using this approach, it appears that I am using a single admin account through to the API, whereas I would like to pass through the session token based on which user is currently using the website.

Is there a standardized way that I can pass through the session token available in service A in the request to service B. Yes the token itself will have been provided from B to A as a result of the login process so service B will have the corresponding session in its session cache.

I’d recommend using the JWT AuthProvider which is ideal for authenticating across multiple Services configured with the same Auth Key as the JWT Token encapsulates a stateless User Session which can be authenticate with multiple different Services without needing to configure them to use any external dependencies.

The JWT docs has some examples of authenticating with a central Auth Server.

The new https://techstacks.io also needs to do this in order transfer the Session from the techstacks.io domain to the www.techstacks.io domain which was documented in the latest release notes.

This looks ideal thanks!, I’ll try implementing it tomorrow and will report back.

I have tried to implement this today, and think I am close.

I added the auth feature in my micro service using the following:

        Plugins.Add(new AuthFeature(
            () => new AuthUserSession(),
            new IAuthProvider[] {
                new JwtAuthProvider(AppSettings) {
                       AuthKey = AesUtils.CreateKey(),
                       RequireSecureConnection =false },
                new CustomCredentialsAuthProvider()
            }
        )
        { HtmlRedirect = null });

and then attempted to use this from my MVC app using:

var authClient = new JsonServiceClient(ConfigurationManager.AppSettings[“Service.Log.URL”]);

            var authResponse = authClient.Get(new Authenticate
            {
                provider = "credentials",
                UserName = "user",
                Password = "pass",
                RememberMe = true,
            });

            var client = new JsonServiceClient(ConfigurationManager.AppSettings["Service.Log.URL"])
            {
                BearerToken = authResponse.BearerToken //Send JWT in HTTP Authorization Request Header
            };
            return client;

The issue I have it seems is that my authresponse is returning as null. and therefore I cannot access the BearerToken so must be doing something in my overridden class.

I have the following CustomCredentials Class:

public class CustomCredentialsAuthProvider : CredentialsAuthProvider
{
    public override bool TryAuthenticate(IServiceBase authService, string userName, string password)
    {
        //Add here your custom auth logic (database calls etc)
        //Return true if credentials are valid, otherwise false
        return true;
    }

    public override IHttpResult OnAuthenticated(IServiceBase authService, IAuthSession session, IAuthTokens tokens, Dictionary<string, string> authInfo) {
        session.FirstName = "Bob";
        var resp = new HttpResult();

        //resp.
        authService.SaveSession(session, SessionExpiry);
        return resp;
    }

}

I wasn’t entirely sure what to do with the response, this used to be a void method, but now requires an HttpResult as a response here.

Replace SaveSession() with base.OnAuthenticated() which calls SaveSession() as well as other Session / AuthEvents.

Return null if successful the IHttpResult is if you want to return an Custom Error or Redirect Response, in this case you should just return the response of base.OnAuthenticated(), e.g:

return base.OnAuthenticated(...);

Of course, that works. Very nice.

A couple of small questions.

  • I have not implemented a session cache provider atm, so with the default implementation (as it is now) where is the session currently being stored?
  • I am currently using redis for queueing and intended to use redis as the session store as well so will lookup support for that next. Which mechanism will manage the redis sessions e.g. clear out expired ones ?

The benefit of JWT is that they encapsulate a User Session so doesn’t require any state on the server. If you Authenticate with UseTokenCookie=true then the Session is removed from the server likewise when calling ConvertSessionToToken, the session is removed from the server.

Thanks Mythz, it makes sense.

This has the MVC layer authenticating against the micro services API working well.

The final step is for me to manage the session from the browser to the MVC layer. Up until now this has been handled with an HTTP Context class which backends values in the following way:

    public static string Username
    {
        get
        {
            if (HttpContext.Current == null)
                return string.Empty;
            var sessionVar = HttpContext.Current.Session[usernameSessionVar];
            if (sessionVar != null)
                return sessionVar as string;
            return null;
        }

        set
        {
            HttpContext.Current.Session[usernameSessionVar] = value;
        }
    }

Am I correct that at this layer, I would simply assign the jwt token to the HttpContext e.g. HttpContext.Current.Session[token] = jwtoken; and then change methods to work with that value instead ?

This would require having the base64 key available in this app, do you see a problem with that ?

Is there a better way I could manage this ?

ASP.NET Sessions are completely unrelated to ServiceStack Sessions. To access the ServiceStack Session from an MVC Controller you can inherit ServiceStackController From ServiceStack.Mvc NuGet package and call SessionAs<T>, e.g:

var session = base.SessionAs<AuthUserSession>();

Thanks all this is very helpful,

The final item I am facing is the need for some of the session meta (set in service B) to be available in service A.

Specifically, I have extended permission, role and account related properties to a custom session and this works well internally in service B, however service A (MVC) requires to know whether a user is an admin at the calling level in order to hide/show functionality.

What is the correct way to handle that?

  1. Do I extend the AuthReponse attained when authenticating to return what i need?
  2. Do I Decode the Session from token in service A ?This would allow me to transpose to the ASP.Net Session
  3. Retain that part of the authentication process in service A (this is what I was doing prior to jwt and prefer not to house logic in both places) ?
  4. Another way ?

It seems maybe the AuthFilterContext which allows me to modify the authreponse may be what I need ?

Or I can use the Meta property, maybe that’s the best way…

What is the correct way to access the JWT from within a service method:

    public object Any(SomeObjectRequest request)
    {

        // get session from jwt here...

        using (var db = DbFactory.Open())
        {
            response = xxx
        }
        return response;
    }

When this service is not ASP MVC

The JWT is used to populate the Session which you would access as you normally would:

var session = SessionAs<AuthUserSession>();

If you need the actual JWT string token yourself you can access it from:

var jwt = Request.GetJwtToken();