Delivering the Expected - Solteq Developer Blog

JWT Tokens Revisited

Title image

As with any new technology, the first implementation is not always the best one. We had to adjust JWT token handling in the front-end and now I’m going to share those experiences.

This post is a follow-up to the previous post which I wrote, called Securing Microservices with JWT tokens. I encourage you to read that first.

Recap

At the moment, JWT tokens have been in production use for about half a year and there haven’t been any problems with the tokens itself. The only problem that we had encountered was caused by us misconfiguring the cloud environment.

Miserable failure

We have really tried to create stateless services for our microservice architecture, but there was one time when we failed to do so. It was our authentication service which acted as a proxy between microservices and old OAuth2 authentication server. It turned out that we forgot the session which was generated while the user was being authenticated and redirected to the OAuth2 server. After we made our services more resilient by duplicating them, we forgot to use the sticky sessions so that the users would have been always redirected back to the same authentication service instance. This caused occasional failures to the user authentication process as there were no existing session for that user when returned from the OAuth2-server and thus service generated an error. This caused us some gray hairs before we realized the actual problems, the fix was a no-brainer.

Hopefully picture can illustrate the situation more:

Authentication diagram

Change local storage to cookies

At the beginning we used the Authorization-request header to pass JWT token to the back-end when performing requests from the UI. The token itself was stored in browser’s local storage. It turned out, that this wasn’t the best way when security was in concern. For UI to be able to set JWT token to HTTP headers, it must be able to read JWT token from somewhere.

Using browser’s local storage to store JWT token exposes it to possible XSS (Cross site scripting) attacks. As JavaScript is able to read the JWT token, it’s also possible that some third party malicious JavaScript-code could read it and send the token to a third party attacker. This would require an XSS-vulnerability to exist somewhere in our SPA application, but we didn’t want to take that change.

To reduce the risk of leaking JWT token into wrong hands, we changed the local store to the HTTP only cookies. JavaScript-code cannot access HTTP-only cookies but they’re still included in the back-end calls by the browser itself, not JavaScript. Our authentication service sets authentication cookie to response headers instead of returning the JWT token in the response. It’s crucial that you use HTTP only cookie because without setting the httpOnly-flag, JavaScript is still able to read the cookie’s content and the possibility of an XSS attack remains.

As the SPA cannot access JWT token anymore, it doesn’t have knowledge of current user’s information (username, roles, etc). Thus we needed to implement an endpoint to the back-end service which could be used to fetch user’s details for UI. The endpoint has been secured so that UI (browser) must send authentication cookie along with the request to be able to access the endpoint.

Conclusion

JWT tokens have still been valid decision to secure our microservices and with authentication cookies, capturing token by a possible attacker is even harder than before.

You can read more about the subject from this related posts:




Join us?

See what we have to offer - Careers