JWT Best Practises

Authentication and Authorisation?

Reference URL: https://dev.to/sebastiandg7/how-do-you-handle-role-permissions-updates-with-jwt-3778

So, what’s the best way to make use of JWT?

It allows us to keep identity (who you are), authorisation (what can you access) and whatever else the application server and authorisation server thinks would be useful for the application server whenever it gets a request from the client. So do we then keep a list of grants and privileges in the JWT? Well…. I did a bit of research on this to finally land on the afore mentioned URL.

It seems, its best to have just identity information in a JWT and not load it with authorisation information or much else. Here are the reasons:

  • Because roles and permissions (authorisation info) change frequently with the evolution of the application and the client, “Conflating authorization (roles, permissions, etc.) and identity (name, email, userId, etc) into the same token can lead to a bunch of problems.”

  • By keeping JWT slim, with just identity information and it’s expiration time, it minimises request processing latency. Take this with a pinch of salt though, because whenever the application server gets a request, it may have to retrieve the user’s grants… unless the application just relies on several well defined roles. And it already knows what access to provide with those roles.

  • For authorisation, let the client / browser query the application server. Or even better, pin it with an observable or subscription like event driven mechanism to inform the client if there is a change. But it’s not strictly necessary to do this as well, as the authorisation and privilege list is not going to change much.

In summary, keep the JWT small with just the user’s identity. Otherwise, the JWT size will keep increasing as app features increase. Just let the authorisation server focus on the user identity, authorisation, password storage, token issuance, forget password, etc. Then, use the token to lookup user permissions on the application server, making this transaction stateless every time and keeping things simple.

HTTP Requests

  • As a general rule, do not send any data as URL encoded search parameter strings which can be viewed on the URL.

Between Microservices

So, what’s the best way for communication between microservices?

Its best for JWTs to use asymmetric key pairs, so that the consuming microservice use’s the API server’s shared public key, while the API server uses its private key to validate the token.

See https://blog.cacoveanu.com/2018b/2018.11.28.asymmetric_jwt.html for detailed explanations.

The JWT token is created by the calling microservice with the public key using a code similar to the one below:

  var token = Jwts.builder()
      .signWith(Keys.ApiPublicKey, SignatureAlgorithm.RS512)
      .setHeaderParam("typ", SecurityConstants.TOKEN_TYPE)
      .setIssuer(SecurityConstants.TOKEN_ISSUER)
      .setAudience(SecurityConstants.TOKEN_AUDIENCE)
      .setSubject(remoteApi01.getApiKey())
      .setExpiration(expiry)
      .compact();

The JWT token is verified using a code similar to the one below:

  var ApiPrivateKey = SecurityConstants.ApiPrivateKey.getBytes();

  var parsedToken = Jwts.parser()
      .setSigningKey(ApiPrivateKey)
      .parseClaimsJws(token.replace("Bearer ", ""));

Between Browser Applications

Browser pages for the same application may be created separately, routed from one page to another. As long as they communicate with the application server with the same JWT (from the previous page), they allow the user to move seamlessly between web pages.

The recommended approach for the login page, is to store the JWT in the HTML5 web storage and subsequent applications / pages can then retrieve this for the current web session and use it for HTTP requests to the application server.