From stateful to stateless RESTful security using Spring and JWTs – Part 4 (JWT-based authentication)

We previously managed to move to statelessness, which is a good step forward. We managed to get rid of Session objects!

However we did it by adopting a very naive (shall we even say: pretty much unusable!) solution for identifying a user. We still need to find a system to make those tokens secure, tamper-proof and bearing a verifiable origin. Lucky us, JWTs will be our salvation!

So suit up and get ready to dive into the fantastic world of JSON Web Tokens! (or click on this link to get that GitHub code. It’s a free world, right? 😉 )

Related posts

So, what’s a JWT anyway?

Authenticating against a RESTful API actually implies having a server recognize a given user and save that proof-of-authentication somehow (in a Session object or in a token). If we think “stateless” then the server can’t keep that proof-of-authentication, so it needs to transmit it to the user’s browser.
We certainly don’t want the user (or any other malevolent entity!) to mess with that proof-of-authentication, so it has to be secured against anyone but the server itself. This way, when the user sends that proof-of-authentication back to the server to access a REST endpoint, the server can be 100% sure of the authenticity of the client.

A JSON Web Token (JWT) is an open standard (RFC 7519) that defines a compact and self-contained way for securely transmitting information between parties as a JSON object (quoted from jwt.io).

Compact is nice, but we’ll later see that it’s not as compact as a JSESSIONID. Food for thought for a forthcoming post…
Self-contained: it’d better be, since we’ve giving up on keeping a state on the server-side.
Securely transmits information between parties? We hit the jackpot!
JWTs are also digitally signed, so no tampering allowed there.

A JWT is composed of three parts:

  1. A header, which indicates the type of the token being exchanged (and we set that to… “JWT”, correct!) and the hashing algorithm applied on it.
  2. A payload (body) carrying a series of claims, aka statements about the authenticated user (full name, admin or not…), who issued the JWT, when it expires, etc.
  3. A signature, which allows us to verify that the JWT emitter is indeed who it says he is and that the message hasn’t been tampered with.

In practice, JWTs are typically exchanged in the Authorization header, using the Bearer schema. They are meant to be stored by the client, usually in the browser’s local storage or in a cookie (more on that in a forthcoming post).

Give me a JWT

Since we don’t want to reinvent the wheel, let’s start by importing a library to generate those JWTs. I’ve decided to go with jjwt, by there are plenty of other great projects for that purpose. Just check the list on jwt.io.

Beyond a few constants, our SecurityConfiguration stays the same:

That secret key will be used to sign our emitted token: that’s essential to ensure that no one has tampered with the token’s listed claims!

Moving on to the TokenBasedAuthenticationFilter class, we will now generate a real token at user authentication, using the jjwt library:

By using the Jwts builder, we specify three reserved claims: the token ID (“jti“), its subject (“sub“) used to identify the principal (in our context, that’s the user’s username), and an expiration time (“exp“) that indicates the time at which the token ceases to be valid.

The important bit here is the token ID, which we generate randomly. By adding entropy (aka randomness) to the token, we can mitigate replay attacks by generating new tokens (with new IDs) at short intervals. Of course for this to make any sense the expiration claim, set by the TOKEN_LIFETIME constant, should be lowered from 7 days to, say, 15 or 30 minutes.

The library then allows us to sign the token with a specified algorithm and a secret which, it goes without saying, is only effective if not leaked.

Finally the compact() method generates our token while also compacting it according to the official specifications.

Leeloo Dallas multipass

So now a client needs to access our RESTful API and sends his/her token on the Authorization HTTP header. The back end needs to verify the token signature and extract the claims from it. In our case, the only claims we’ll get is the subject (the user’s username) and the expiration time. Let’s reexamine our TokenBasedAuthorizationFilter from last time:

After retrieving it from the HTTP request, the submitted token is parsed to extract the claims from its body section. In the process, the secret key is used to verify the token’s signature and make sure it has not been tampered with.

In our tutorial, we merely want to know who that user pretending he’s logged is, so we obtain the subject (username) from the token’s claims and pass it to the SecurityContextHolder. Later in the flow of events, a @Controller‘s method will be able to leverage the Principal object to obtain that username. You can also provide the user’s roles, to be fed to the security context as the “authorities” parameter (currently set to an empty collection).

Just make sure you leave that credentials parameter to null: you sure don’t want to carry the user’s password around in that token! Don’t forget that, although the token is signed to make sure it’s authentic, it is NOT encrypted. The reason it looks unreadable is because it is base64-encoded, but anyone with a bit of knowledge can read its claims.
Try pasting the JWT below on this website for decoding:

The moral of the story is: never pass sensitive data into a JWT!!!

Are we done then?

Congratulations, you now have the basics to implement stateless JWT authentication on your Spring-based RESTful API!

Before you rush out and add token-based security to your new application, we still have a couple of things to discuss.
One of those is the storage of that token on the client side. If you decide to store it in a cookie, you might want to review the options in terms of defending against CSRF attacks. I will also provide you with a list of useful web resources I used to write this tutorial. There are people out there who have really studied the subject and explained the core of it in simple terms, they should definitely be thanked for that!

Finally, there’s an important question we need to answer: should you actually use JWT-based authentication?
This is definitely a tricky decision to make, and I’ll try to expose as clearly as possible my thoughts on the pros and cons of going stateless.

Until next time,

Cheers!

 

Leave a Reply

Your email address will not be published. Required fields are marked *