The cost of the authentication method

time to read 3 min | 565 words

You might have noticed that we are doing a lot of work around performance. Some of this work can be done with just optimizing the way we are doing certain operations, but for some things, we cannot just optimize things, and a behavior change is also required.

In this case, we are talking about the authentication method for RavenDB. The current way it works goes something like this.

  • The user is making a request to a RavenDB server.
  • The server requires security, and ask the user to authenticate. For this case, we’ll sue API Keys.
  • The user & server will have a side channel discussion for authentication via API Keys, which will result in a token.
  • This token is sent as a header in all future requests.
  • The token is cryptographically signed, so the server can validate that it is valid.

So far, so good, but this does pose some issues.

To start with, we took a lot from OAuth, so that means that we assume that there are multiple entities in this. The user, the server and the authenticator, and the use of cryptographic signature is meant to ensure that the server can trust the token generated by the authenticator and served by the user.

However, in pretty much all cases, the server and the authenticator are the same. There are some special cases relating to replication and load balancing, but they aren’t relevant at this point, and we can work around them if need be.

And we’ll want to do that. The reason that this is problematic is very simple, right now, we need to cryptographically validate the token on every single request. And that is expensive. Of course, in some cases, it is actually meant to be expensive, that is why it is secure.

So we need to reduce this cost, and we can reduce that by saying that we can just keep a simple token. Conceptually, this now becomes:

  • The user is making a request to a RavenDB server.
  • The server requires security, and ask the user to authenticate. For this case, we’ll sue API Keys.
  • The user & server will have a side channel discussion for authentication via API Keys, which will result in a token.
  • This token is sent as a header in all future requests.
  • The token is just a unique id (guid), which is stored on the server memory.

Because the token is unique, and per server, we don’t need to do any crypto validation on the value. We can just check if the value is in our memory, and that would be it.

The first reaction we typically get is “but what about security? someone can re-use that guid to authenticate as someone else”. That assumes that you can sniff the conversation between client and server. If you can do that, then you are probably already don’t care about security, since you aren’t using HTTPS. But note that the same behavior occurs using the crypto token as well. If you manage to take that, you can present it to the server as your own token, and the server can’t tell the difference between a valid client and a malicious one.

The good part of this is that now the authentication part of the request is a dictionary lookup, instead of cryptographic signature validation. And the performance of authenticated requests is much higher.