How to select a JOSE / JWT cryptographic algorithm for your application
JavaScript Object Signing and Encryption (JOSE) has adopted an array of standard cryptographic algorithms, including new Edwardscurve algorithms (added in 2017). So which algorithm should you use to secure your JSON Web Tokens (JWT) or other objects in your application? This guide will provide you with the basic criteria for making an informed choice. But do also consult with articles, literature and experts in the field, to double check your assumptions and make sure nothing critical is missed.
The common data security objectives
Our needs to secure data, such as tokens, typically stem from one or more concerns:
Objective: Verify data has not been tampered with 
Objective: The origin of the data can be verified 
Objective: The origin of the data must be verifiable by others 
Objective: Data is kept secret from unauthorised parties and processes 
Understanding which security aspect(s) we're after is the first step in selecting an appropriate JOSE algorithm.
Available JOSE algorithm classes
JOSE provides three distinct classes of cryptographic algorithms to cater for the four security objectives, with partially overlapping properties:
Integrity  Authentication  Nonrepudiation  Confidentiality  

HMAC 
✔  ✔  
Digital signatures  ✔  ✔  ✔  
Authenticated encryption  ✔  ✔  ✔ 
HMAC algorithms: A special super efficient hash (HMAC) for ensuring the integrity and authenticity of data. In order to compute an HMAC you need a secret key.
Digital signatures: Offer the properties of HMAC, plus cryptographic nonrepudiation (enabling others than the signer to check the signature's validity). Digital signatures are based on public / private key cryptography. Require a public / private key pair (of type RSA, elliptic curve (EC), or Edwardscurve Octet Key Pair (OKP)).
Authenticated encryption: Encrypt data, while also ensuring its integrity and authenticity (like HMAC). JOSE offers encryption with public / private keys, with secret (shared) keys and with passwords.
1. Hashbased Message Authentication Code (HMAC)
Provide  Integrity, Authentication 

JOSE format  JSON Web Signature (JWS) 
Key type  Secret key 
Algorithms 
HMAC with SHA2:

Use cases 

Notes 

The HMAC algorithms (with JOSE alg identifiers HS256, HS384 and HS512) are ideal for securing tokens and other information that needs to be sent out or stored externally, in order to be eventually consumed by the issuing application. The key concerns here are ensuring 1) the integrity of the data when we get it back, and 2) that the data was actually produced by us.
A good example is employing HMACsecured JWTs for generating stateless session cookies. The JWT can include the ID and other information about the loggedin user. When a cookie is received by the web app the HMAC is recomputed and compared to that of the JWT. If the two HMACs don't match we can assume that the cookie has been tampered with, or isn't ours.
Example JWT claims for a stateless session cookie:
{
"sub" : "user12345",
"email" : "[email protected]",
"login_ip" : "172.16.254.1",
"exp" : 1471102267
}
A common misconception is that message authentication codes qualify as digital signatures. They don't! That's because verification requires access to the original secret key used to compute the HMAC, and by its nature you cannot share that key with others without also giving them the ability to generate their own HMACs. If you want nonrepudiation use RSA, EC or EdDSA signatures.
2. Digital signatures
Provide  Integrity, Authentication, Nonrepudiation 

JOSE format  JSON Web Signature (JWS) 
Key type  Public / private key pair:

Algorithms 
RSA signature with PKCS #1 and SHA2:

Use cases 

Notes 

Digital signatures are suited for issuing of tokens, statements, assertions and documents which integrity and authenticity must be verifiable by other parties.
Example uses:
Identity tokens issued by an OpenID provider, which a relying party needs to verify in order to sign in a user.
Access tokens issued by an OAuth 2.0 server, which the resource servers / web API must verify before serving the request.
Digital signatures work only with public / private keys:
The issuer needs to generate a public / private key pair before it can sign JWTs or other objects.
The signature is computed with the private key, which must be kept secure at all times, otherwise there is risk of impersonation.
The signature of a JWT or JWS object is validated with the public key. The method by which recipients can discover and download the public key are application specific. OpenID Connect servers for example publishe their public keys at a URL in JWK format.
Which digital signature algorithm to choose?
If you're looking for broad support, choose RS256. This algorithm is based on RSA PKCS #1, which is still the most widely used standard for public / private key cryptography. Any decent JWT library should support it. RSxxx signatures also take very little CPU time to verify (good for ensuring quick processing of access tokens at resource servers). 2048 bits is the recommended RSA key length.
The ESxxx signature algorithms use Elliptic Curve (EC) cryptography. They require shorter keys and produce mush smaller signatures (of equivalent to RSA strength). EC signatures have one disadvantage though: their verification is significantly slower.
The new Edxxx algorithms offer the best sign / validate performance mix. Signing in particular is boosted 62x over 2048bit RSA and 14x over EC DSA with P265 curve.
We have examples for RSA, EC and EdDSA signed JWTs.
3. Authenticated encryption
Provide  Confidentiality, Integrity, Authentication 

JOSE format  JSON Web Encryption (JWE) 
Key type 

Algorithms 
Public / private key encryption:

Use cases 

Notes 

JOSE provides encryption with the following:
A secret key in case you want to encrypt data for yourself. If the secret key is shared with other parties (by some outofband mean), they can also encrypt data / decrypt ciphertext with it. Check out the table above for the available secret key encryption algorithms.
A public key (RSA, EC or OKP) provided by recipient. OpenID Connect providers for example publish their public keys in JWK format at a discoverable URL. The recipient can then decrypt the JWT / JOSE object with its matching private key. Public / private key cryptography is ideal in situations where communicating a secret key outofband is not possible or feasible.
A password if you want to encrypt data with some phrase that you can remember.
Encryption in JOSE is always authenticated, meaning that the ciphertext's integrity is protected from tampering. Authenticated encryption thus makes nesting an HMAC JWT inside a JSON Web Encryption (JWE) redundant; use just JWE encryption.
JWE encryption is a "two step" process:
The data, or content, is always encrypted with an AES key (called the Content Encryption Key, or CEK), and each JWT / JWE object uses a different CEK. The Nimbus library will automatically generate this AES key for you, and its length will depend on the enc (encryption method) header parameter (e.g. an
"enc":"A128GCM"
will cause a 128bit AES key to be generated). Besides the choice of three AES key lengths (128, 198 and 256), JOSE supports two modes for content encryption: AxxxCBCHSxxx and AxxxGCM. The AxxxCBCHSxxx mode is typically the more widely supported.The second step is encrypting, also called wrapping, the generated AES CEK with the input key, i.e. the secret key, the public key or the password that you provided. This is specified by the alg JWE header parameter. In case you want to skip the second step, and provide the AES CEK directly, choose direct encryption and specify an
"alg":"dir"
JWE header parameter.
Example JWE header where the content is encrypted with 128bit AES in GCM mode, while the AES CEK itself is encrypted with a public RSA key (using RSA OAEP encryption):
{
"alg" : "RSAOAEP",
"enc" : "A128GCM"
}
You can check out the example for encrypting a JWT with an RSA public key.
Nested signing and encryption
A signed JWT / JWS object can be additionally encrypted, thus providing integrity, authenticity, nonrepudiation and confidentiality to data.
This is achieved by simple nesting (see example):
The JWT is signed with a private RSA, EC or OKP key.
The signed JWT then becomes the payload (plaintext) of a JWE object, which is encrypted with either the public key (RSA, EC, OKP) of the recipient, or with a secret key that has been shared between the two parties.
Processing a nested JWT works backwards:
The JWE object is decrypted with the appropriate key (private key for RSA, EC or OKP, or established secret key).
The extracted payload (plain text) is then parsed as a signed JWT, and verified with the issuer's public key (RSA, EC or OKP).
The Nimbus JOSE+JWT library provides a complete framework for handling nested JWTs.
Algorithm choices in OpenID Connect
The following rules can give you an idea of which ID token algorithms are possible, given a client registration:
A client with a client_secret can receive ID tokens secured with HMAC (where the client_secret serves as the HMAC secret key) or with a signature (RSA, EC or EdDSA). In order to verify an RSA, EC or EdDSA signed ID token the client simply needs to retrieve the matching public key of the OpenID provider (from its JWK set URL).
A client with a client_secret can also receive encrypted ID tokens, where the client_secret is used to derive a secret AES key from it.
Issued client_secrets must be sufficiently long to fit the required secret key length if HMAC is used. For example, a 256 bit client_secret permits HMAC with HS256.
In order for a client to receive RSA or ECDH encrypted ID tokens, it must have a public RSA, EC or OKP key registered with the OpenID provider.
OpenID Connect also permits clients without a client_secret. Such clients need to register a public RSA, EC or OKP key with the OpenID provider, and use that key to authenticate (via JWT) at the token endpoint. The ID token may be encrypted to that public key as explained above.
comments powered by Disqus