“JSON Web Tokens are an open, industry standard RFC 7519 method for representing claims securely between two parties.”JWT.IO
If you’ve worked on implementing authentication or authorization within an API context, you’ll be familiar with the notion of token based access control, whereby a client proves it’s allowed to access resources supplied by an API by sending a token alongside its request. Access tokens are a bit like passwords, but for machines — so they’re typically as long and random as possible. More powerful token systems like OAuth allow access control to API resources to be segregated by applications (Facebook’s API is a good example), where applications have only the permissions
(sometimes called “scopes”) they need.
The primary difference between JWT and other token based authentication schemes is that while a standard API token is typically a randomized string of some kind, a JWT actually contains information. It has three parts: a header (containing metadata about the token itself), a payload (containing application specific data), and a cryptographic signature. While JWT’s can be encrypted to hide that information, what’s more important is the signature. Why?
The signature of a JWT is cryptographically created by the issuer of the token (typically the API’s authentication/identity provider), proving its origin and that it has not been tampered with. This mechanism allows you to safely include metadata in the JWT payload, such as for example the user ID of the authenticated client, and other systems may then rely on that metadata being correct and immutable. If the content is changed in some way, then the cryptographic signature will not match.
It allows the token to be used with other API’s to authorize a client, without the other API needing to independently validate the authorization with an identity service. This makes JWT’s a great fit for microservice architectures — it de-couples proof-of-authorization from the issuing server. API’s can simply validate the token’s signature, decode the payload (a base-64 encoded JSON object) and get the user’s identity or any other relevant metadata.
Let’s give a more concrete example of how JWT could be implemented as the primary authentication and authorization method in a microservice based system.
“IdentityAPI” is a microservice with a database containing identity and authorization data such as users, passwords and roles. It provides typical endpoints to authenticate users, such as “login”, “create user”, “reset password” and so on. Functionally it’s the same as any other such service, except instead of setting a cookie or returning a randomized access token, it generates a JWT and digitally signs it with a secret (“signing”) key (a long, randomized token stored securely). The resulting signature is appended to the token, and returned to the authenticating client.
“OrderAPI” is another microservice allowing authenticated users to create an order. When an order is submitted, the JWT is included (for example in the “Authorization” header). The OrderAPI also knows the secret key, and is able to “validate” the JWT by re-calculating the signature using the secret key and comparing it to the signature contained in the JWT. It can then trust the JWT payload was set by IdentityAPI, including the userID, authorize the order creation and associate the order to the user in the JWT.
JWT is a more complex system of authentication than bearer tokens or framework provided session cookies, and as with all security concepts, the more complex something is the more ways it can go wrong or be exploited by adversarial third parties. There are some very informative and complete guides out there – I found Hacking JSON Web Tokens by Vickie Li to be a particularly illuminating read. But in short, with JWT’s you need to make sure you lock down every variable as much as possible (for example the signing algorithm) and treat a JWT as untrusted system input until it has been completely validated. If any of the metadata included in the payload is sensitive in any way (for example a user’s email address), definitely consider using asymmetric encryption to hide that
It’s also very important that you treat your secret signing key the same way you would other sensitive secrets like your database password or API keys, and store it securely. For example, if you’re using AWS, put it in AWS Secrets Manager. If someone obtains your secret signing key they potentially gain arbitrary access to every part of your system using JWT’s!
It’s also worth considering whether you need to be able to deactivate users and/or their active sessions in your system. In this case, relying on token expiry may not be sufficient for your requirements, and you will need to do additional implementation work. For example, you could implement a user/session blacklist in your API gateway, or broadcast “deactivate” events
on your service bus. This kind of requirement can potentially impact every part of your system using JWT’s.
Finally, always make sure the library you use for creating and validating JWT’s functions correctly, as there are quite a few known-bad or known-incomplete implementations out there. (JWT.IO maintains a pretty comprehensive list). While normally you wouldn’t unit test a third party library, for JWT’s it’s not a bad idea to validate your library doesn’t e.g. allow the ‘none’ signing algorithm when validating tokens.
I hope this has been a good introduction into implementing JSON Web Tokens. If you’re interested in learning more, JWT.io is a great resource — it has a very useful online debugger you can paste tokens into to see what’s in them and test if they’ve been signed correctly. (Don’t use your production signing key in a third party website of course!)
As with any technology, if you’re considering implementing JWT’s, make sure they’re the right tool for the job (are you sure you need them?), and do a considered cost/benefit analysis. If you’ve decided to implement them and are at the design stage, it helps a lot to do a full flow analysis with sequence diagrams to understand what you’ll need to do. JWT’s are a powerful and flexible technology, but you should be clear about the complexity, development and maintenance implications.