JWTs are JSON web tokens that are widely utilized in OAuth and OpenID Connect. In fact, their application is so popular that the main principles of their use are quite often overlooked. However, the basics should not be forgotten.
So, that is why we decided to brush some dust off the fundamentals of JWTs. What are JWTs? How should they be used? Are they really secure?
1. What are JWTs?
There are three basic things that you absolutely need to know about JWTs:
· JWT stands for “JSON web token” and is pronounced as jot. It is not a protocol but a format. It is a standard defined in RFC 7519.
· JWTs’ function is to pass a JSON message between two parties in a compact and URL-safe way.
· The token structure depends on its type: whether it is signed (JWS) or encrypted (JWE). If the token is signed, it will have three sections: the header, the payload, and the signature. If the token is encrypted, it consists of five parts: the header, the encrypted key, the initialization vector, the ciphertext (payload), and the authentication tag. All parts are separated with dots and base64-encoded.
2. What are the main areas of JWT application?
The most common scenario is JTWs being used as Access Tokens, and ID Tokens in OAuth and OpenID Connect flows. They can serve different purposes too — for example, request objects in OIDC and other generic use-cases.
3. What are the best algorithms to use with JWTs?
The JWA RFC lists all available algorithms that can be used to sign or encrypt JWTs. It also tells you which algorithms are recommended to be implemented by clients and servers, given the current knowledge of cryptography security.
Currently, the most recommended algorithm for signing is ES256 (The Elliptic Curve Digital Signature Algorithm (ECDSA) using P-256 and SHA-256). It is preferred over the most popular one — RS256 (RSASSA-PKCS1-v1_5 using SHA-256), as it is much faster than the well-tried RS256. While the latter is considered the most studied and developed, we recommend using ES256 (if your setup and clients allow this).
Using symmetric keys is not recommended. However, if there is a strong need, HS256 (HMAC using SHA-256) should be your choice.
As a side note, it needs to be emphasized that no matter the type of the token — JWS or JWE, they contain an alg claim in the header. This claim indicates which algorithm has been used for signing or encryption. This claim should always be checked with a whitelist of algorithms accepted by your system.
Whitelisting helps mitigate attacks connected to tampering with tokens when the final goal would be to force you to use different, less secure algorithms to verify the signature or decrypt the token. It is also more efficient than blacklisting, as it prevents issues with case-sensitivity.
4. How do I work with the signature in JWS?
The main thing to remember about the signature in JWS is that it is used to sign both the payload and the token header. Therefore, special attention should be paid to making any changes, whether it is changing the claims’ values or mere adding or removing spaces or line breaks.
· To ensure that tokens are not duplicated (two tokens with the same signature), it is suggested to add a random ID of the token in the jti claim. Many Authorization Servers provide this opportunity.
· To validate signatures, keys and certificates are needed. They can be obtained from the Authorization Server. The best practice is to always use an endpoint and download certificates and keys dynamically. This enables an easy rotation of keys, which would not break the implementation.
· Don’t forget to check the keys and certificates sent in the header of the JWS against a whitelist or validate the trust chain for certificates. Also, remember to whitelist the alg in the header.
5. Can I use symmetric signing?
Try to avoid it.
This is because using symmetric signing presupposes a large number of parties knowing the shared secret. The more sophisticated structure, the more difficult it becomes to guard the secret’s safety and replace it. Moreover, symmetric signing complicates the proof of signature: any party with access to the secret can also sign tokens.
Instead of symmetric, choose asymmetric signing. This way, you’ll be sure that the JWT is signed by the entity having the private key and make the security management less complicated.
6. How do I use JWTs as access tokens?
JWTs are by-value tokens, which means that they contain data. It is also important to remember that the data in JWTs used as access tokens are intended for the API developers so that APIs decode and validate the token. However, if JWTs are issued to be used as access tokens to your clients, there is a risk that client developers will access this data.
Therefore:
· If you choose to issue JWTs to your clients as Access Tokens, be prepared that introducing changes may cause problems with app integrations.
· Don’t put sensitive or personally identifiable information in the token. If it cannot be removed from the token, consider switching to Phantom Tokens or Split Tokens, where an opaque token is used outside your infrastructure.
· Don’t put any valuable data about your APIs in JWTs.
· Consider using Proof of Possession tokens instead of Bearer tokens by adding a confirmation claim. This will mitigate the risks of unwanted access.
7. Is there any other method of increasing the security of sensitive data?
Using Pairwise Pseudonymous Identifiers (PPID) can be a good option.
Introduced by the OpenID Connect Standard, PPID can be used as a substitute for an explicit user ID. It helps to improve users’ privacy by assigning users with opaque and random identifiers that are unique to different clients. Thanks to PPID, the client would still be able to identify the user but will not get any excess information.
8. What are the most critical areas to keep in mind when working with JWTs?
Many critical areas need to be considered when working with JWTs to ensure the appropriate security level. We mention just a few of them:
· The signature of the token
The best practice is to always validate an incoming JWT: whether it is in the external or internal network. The environment settings should never serve as factors determining the security of your infrastructure. The only case when checking the signature of the token can be omitted is when it is received from the token endpoint of the Authorization Server using TLS (this rule doesn’t apply to situations with the implicit flow or when a token is sent back to the client through a redirect URI).
· The issuer of the token
This factor can be found in the iss claim, which should be checked against a whitelist. In other words, if the token contains the iss claim, the system should always confirm that the keys used to sign or encrypt this token belong to the issuer.
If you’re using OpenID Connect, the issuer must be a URL using the https scheme. This way, it is much easier to confirm the ownership of the keys or certificates. Thus, it’s good practice to always use such URLs as the issuer value. If this is not the case, you should make sure to get to know how to check this ownership.
Remember that the iss claim’s value should match exactly the value you expect it to be. If you expect the issuer to be https://example.com, this is not the same as https://example.com/secure!
· The audience of the token
The information about the audience of the token is located in the aud claim. It should always be checked by the resource center and confronted with a whitelist to ensure that the token has been issued for an audience that beholds the server. Any requests intended for different audiences should be rejected.
Such an approach allows to mitigate attack scenarios when one resource server would try to gain access to information on a different resource server with obtained genuine Access Token, initially intended for it. Therefore, it is crucial to use the URL of the API that the Access Tokens are intended for, while an ID token must contain the client ID in the aud claim as it is expected to be decoded by the client to make the data available.
· The intended use of the token
As we mentioned before, JWTs can be used for various purposes and thus function as Access Tokens, ID Tokens, or other types. Therefore, it is necessary to differentiate these types and validate JWTs to ensure they are used as intended.
Several techniques can be used to ensure that:
- Checking the scope of the token (ID tokens don’t have scopes, Access Tokens do);
- Checking the values of the aud claim
- Checking other claims (not-yet-standardized typ claim set to at+JWT for Access tokens is used by some authorization services; the Curity Identity Server, for instance, uses a purpose claim: with values set either to access token or id_token).
9. What about expiration, issued time, and clock skew?
Once issued and delivered to a recipient, JWTs are very hard to revoke. Therefore, it is necessary to set a short expiration time for your tokens. The recommended cycle is several minutes or hours at maximum.
To set this parameter, three claims can be used. Exp claim, containing the expiration time, is the most popular one. However, two others can be used as well: nbf and iat. The nbf claim includes “not-before time” and rejects the token if the current time is before the time in this claim. Iat — “issued at” — can be used to reject tokens that might be too old for your resource server.
Don’t forget that server times might differ between different machines. Consider allowing a clock skew to check the time-based values (30 seconds maximum).
10. So, are JWTs secure?
Short answer: yes, but not by default.
Long answer: JWTs are only deemed secure because they are usually signed or encrypted. However, their security is determined by the way they are used. Therefore, it is essential to follow the advice above to guarantee their security.
To dive deeper into the issue, check out Curity’s resources on API security and other identity and access management topics.