Question

So, I have a web application that makes a lot of requests to the server for data. A project requirement is to have very fast server response times. The server is hosted on a cloud based platform.

The app uses sessions to keep track of user authentication once they've logged in. Since it's hosted on a cloud provider, I'm using a cache to back up session storage (in my case it's Auzre cache, but if you're unfamiliar with that think Redis)

The current flow is like this:

  • The user accesses a resource
  • Trying to get the session based on the session ID via the cache. This is a cache request.
  • User is authenticated via session state (if logged in).
  • Request for data is sent, usually via cache.
  • Data is returned to the user.

The problem with this approach is that it's hitting the cache twice. Removing the session altogether caused a significant speed improvement (about 50%).

I was considering hitting the cache once, asking for both the key I need for the user, and the SessionID to save the extra round trip. However, I've never seen this approach before, and it requires 'rolling my own session' as I'd have to generate the session IDs and such. I feel like there might be a simpler, easier way.

So, what would be the most efficient way to serve the user a resource and authenticate them?


Note: I'm using ASP.NET MVC/ WebAPI with C# but I don't find that very relevant to the question, so I left the language and platform out of the question because of it.

Was it helpful?

Solution

You would want to combine the authenticate and resource request steps into one single request. Not only is this faster, it is also safer than your implementation. Consider the following scenario:

  1. User authenticate to the server. Result is success.
  2. Authentication is changed. (e.g. user changes password, admin decides to lock the user account, etc.)
  3. User makes a request using the sessionID in step 1.

To ensure that the user is not granted access to the resource, you'd want to authenticate the user precisely at step 3. But that doesn't make sense, you've already authenticated this user previously in step 1...

HTTP, in is core, is designed exactly to do this. There are various ways to pass authentication information along with the request, such as:

  1. Write the authentication information in the content (stupid, but works)
  2. Include authentication in the url, e.g. example.com/pic/123?sessionID=abc (better, but makes your url ugly and long)
  3. Store session info in cookie (better, but what if the client does not support cookie? what about cookie expiration?)
  4. Authenticate HTTP header (my best personal recommendation)

HTTP itself has an authenticate header meant to be compatible with "basic authentication" (it is well defined, look it up if you're interested). But you can implement your own custom header.

Any cache lookup is bound to be slow (compared to computation), so you should omit the cache for the authentication part all together. Your server should be stateless; i.e. do not keep track of login sessions. How do you know if the sessionID is valid? Put a timestamp on it. And to avoid others faking the sessionID, sign it as well.

So, your HTTP request would look something like this (pseudo code):

var request = new HttpRequest();
request.url = "example.com/pic/123";
request.Headers["CustomAuth"] = "id=abc&t=123456789&s=01de45890a";

Implement your own signing method, sort of like a hash function (you can use HMAC), and keep the key securely on the server. If the signature matches, you know you've signed this previously at the login, and it has to be from your server. A timestamp helps you detect session expiration and also protect against replay attacks.

Now in your server, do something like this:

public void Get(){
    var authHeader = Request.Headers["CustomAuth"];
    if(!validate(authHeader)){
        Response.StatusCode = 404;
        Response.End();
    }else{
        //something else
    }
}

If you need to do login + session authenticate + resource request in one request, then there're simply just 2 ways for authentication. Users can either provide a username/password combination, or a session key. Think about this scenario, which comes from an API I worked on:

  1. user register with username/password combo
  2. server responds registration success / failure (e.g. username already taken)
  3. if it was a success, user now logins with username/password combo
  4. server returns a session token

Wouldn't it be simpler (and faster) if we do it this way:

  1. user register with username/password combo
  2. if it is success, respond "reg success" and "sessionToken=xxxxxx". if it is failure, respond "reg failure".

I hope this give you some idea.

OTHER TIPS

Also, you can remove the authentication at the server end by modifying / restricting settings on the server to cater to requests coming only from the ip(s) where your web app is hosted. Your web application will let the request pass to server only if its authenticated and hence all the requests reaching the data server will be served automatically without checking for any authentication. In this case you will just need one cache hit to check if the user is authenticated and straight away hit the server.

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top