JWT, OAuth, and Algorithm Choices
Implementing systems that securely authenticate users and authorize their activities within applications can involve multiple interactions that cross trust boundaries. When applications are written in different languages, live in different environments, but still want to share data with each other what are the options?
- Don’t start rolling your own crypto.
- Don’t overcomplicate it
- Don’t use usernames and passwords
- Do use industry standards
The following scenario details a common situation between two business applications owned by the same business. Acme corp has a mobile application “Acme DB Viewer” that provides its users with a friendly mobile interface for its field agents to update and view key records they need to do their work. Other app, a recently developed application, has some data from a different database that the users of the “Acme DB Viewer” app would also like to see as it will help them make better decisions in the field.
Below is a data flow diagram for the two applications:
The boxes around the components are environments. The boundaries around these environments denote trust boundaries. Red trust boundaries mean the environment is “trusted”.
How can Other App authenticate requests for data from the “Acme DB Viewer” mobile application users? How can it authorize them? Developers are probably familiar with two technologies that are helpful in this area: JWT (JSON Web Tokens) and OAuth. Which to use in this scenario? First, it is important to note that JWT is just a format for a token while OAuth is a protocol for authorization, specifying how securely deal with these tokens. OAuth can use JWT based tokens. So, should the developers in this scenario use OAuth? Probably not, but they could. OAuth excels at delegating access to resources for its users, however this flexibility also means more implementation complexity.
First, an important claim we will back up with the rest of this post: JWT is not the solution to your problem. In this case the developers can use JWT and a simple protocol for exchanging and managing these tokens. JWTs are digitally signed JSON documents, and that is it. In isolation the only security problem JWT solves is giving us a reliable implementation of common cryptographic chores. It will prevent implementation mistakes of getting tricky cryptographic code just-so. The solution is solely in how we build trust relationships (which systems trust each other and how they trust each other). We define a very simple protocol of “I am an authenticated user, can I have a JWT please” and “Other App, here is my JWT , can I please have some data?”, in this post. The servers and systems already need to trust each other. Digital signatures (transmitted via JWT) are going to solidify this relationship. If your systems don’t trust each other then JWT and this simple protocol are not for your app. We need OAuth (which can still use JWT).
JWTs in our simple scheme are used as Bearer tokens, that is, a stateless token that must be saved locally in the “Acme DB Viewer” mobile application and refreshed periodically. They are typically passed in HTTP via the authorization header:
Authorization: Bearer <token>
The token has a header, payload, and signature. The header specifies the signature format. The payload is the data with a few defined security claims, such as when the token expires. Other fields are permitted with the token. The signature is a digital signature any receiver of the token can validate. One of the most important decisions when using JWT is which signature algorithm will be used. HS256
uses SHA256 HMAC and requires both parties to have the key. This means either side can generate valid tokens. This is useful when both applications need to generate claims and send them back and forth. RS256
uses RSA and is an asymmetric algorithm. Only one application needs the private key. This is ideal in scenarios where the application does not trust, or will not ever be validating claims from the other application. It also simplifies key management as the application with the public keys does not have to manage the secret key. In this case, Other App only needs the public key component.
The developers decide to use RS256
. This allows the Acme DB application to create a JWT and for Other App to validate the claims in it. It creates a one way trust relationship, meaning Acme DB does not trust Other app at all, but Other App implicitly trusts the Acme DB app to sign claims. Other App then validates the claim and grants access to the data based on the contents of the claim. The claim contents could be a user ID both applications know about, a category of data, or something else. Other App trusts Acme DB to only generate valid claims and make all authorization decisions about what claims are allowed. Other App verifies the JWT and then grants access to its API, and subsequently data, based on the claim.
Now, the Acme DB Viewer mobile application holds a JWT granting it access to Other App data. It passes that to Other App via an HTTP Authorization
header. As long as the token is valid (not expired, good signature, etc.) Other App will grant the owner of that token (Acme DB Viewer) claim based access to its data. When the token expires, Acme DB Viewer can request a new token from Other App.
Guidelines for using JWT:
- Set reasonable token expiration time
- Store them securely in the client
- Use
RS256
when possible - Use trusted libraries for your programming language for all cryptographic operations
- If your use case is complex and involves multiple 3rd parties consider OAuth
- Only grant as much access or privilege as required based on a claim
- Use when stateless non-session based access to an app or API is desired
- Think carefully about HS256 vs. RS256 and how that impacts your application(s) trust relationships
- Stateless JWT are a “super session” that live a long time.
- Never use a JWT in place of a session token
- Consider using the JWT to establish a session token and keeping the expiration on the JWT in the near future
- Avoid putting secret data in the JWT (an attacker should be able to view the payload with no impact)
- If you do use key encryption, you need the
RSA-OAEP
algorithm.
JWT is not without criticism. Choose carefully. You probably don’t need JWT, but in some cases when all the pieces align, it can be a better choice than SAML or OAuth based protocols. Embrace JWT with a healthy dose of skepticism and challenge your use cases for it carefully.