Signed or Encrypted Tokens are not just the next trendy/popular way to authenticate users. They provide great features but when used incorrectly they can expose your application to major security issues.
Please read the following recommendations carefully.
If all parties are able to protect their keys (e.g. private applications), symmetric algorithms are a good choice as they are faster in general. If you use public clients, you should prefer asymmetric algorithms.
This framework provides dozen of signature and encryption algorithms, but you do not need all of them. Most applications only support 1 or 2 algorithms.
You should only use necessary algorithms. For example, HS384 algorithm may be avoided if you already have HS256 and HS512.
Some algorithms are not recommended as there are known security issues:
none: this algorithm is not a real algorithm. It should only be used when other security means exist. An encrypted connection is certainly not enough!
RSA1_5: there are known attacks using this algorithm. If you can avoid its use, then do it.
A small key size is as secured as a password like
123456789. You should use at least 256 bits symmetric keys and at lease 2048 bits RSA keys.
In any case, you MUST use a true random number generator.
It is highly recommended to set the following parameters to yours key:
kid: A unique key ID,
use: indicates the usage of the key. Either
sig (signature/verification) or
alg: the algorithm allowed to be used with this key.
A key is fine but may be cracked e.g. by bruteforce. Changing you keys after several days or weeks is encouraged.
Broadly speaking, you should set your header parameter in the protected header. The use of the unprotected header should be limited to specific use cases.
When using encrypted tokens, the claims
aud should be duplicated into the header. This will avoid unwanted decryption when tokens are sent to a wrong audience.
There is no size constraint for the payload, but when tokens are used in a web context, it should be as small as possible. When used, claims should be limited to the minimum.
Does your application really need to get all the information about a user? For each context, you should choose carefully the claims you want to use.
A unique token ID should be set to all tokens you create. The associated claim is
This claim is highly recommended as it can prevent replay attacks.
The JWT specification introduces several claims to limit the period of validity of the tokens:
exp: expiration time,
iat: issuance time,
nbf: validity point in time.
These claims are not mandatory, but it is recommended to define a period of time for the token validity. When used, the expiration time should be in adaquation with the context of your application. A security token with 2 weeks lifetime is something you should avoid.
iss (issuer) and
aud (audience) should always be set. When duplicated in the header, their values MUST be identical.
Unless you use encrypted tokens, you should use a secured connection when transmitting tokens between parties. A secured communication is not only needed when transmitting tokens, but also when you exchange keys and key sets with other applications.
When you receive a token, the following steps should be followed in this order. If one failed, you you reject the whole token.
Unserialize the token
For each signature/recipient (may be possible when using the Json General Serialization Mode):
Check the complete header (protected and unprotected)
Verify the signature (JWS) or decrypt the token (JWE)
Check the claims in the payload (if any)
You should only use the serialization mode(s) you need. If you intent to use yur tokens in a web context, then use only the Compact Serialization. If an error occurred during this process, you should consider the token as invalid.
Header parameters have to be checked. You should at least check the
alg (algorithm) and
enc (only for JWE) parameters. The
crit (critical) header parameter is always checked.
Please note that unknown header parameters are ignored. If your token is verified, those parameters should not be used.
When used, unprotected header parameters should be handled with care.
Let the component do its job. The most important step for developers is to ensure that the right key/ket set is used.
This step is only required if the payload contains claims. When present, you should always check the
aud claims. Application specific claims should also always checked.
The whole token should be rejected in case of failure. Unknown claims should be ignored.
You should subscribe to security forums of similar websites and have a continuous technological watch. The tokens may be compromised because of malicious attacks on the algorithms, keys or other components related to the JWT (directly or indirectly).
The Security group on Stack Exchange is a good start.