JWT Validation
Last updated
Last updated
This article will explain some alternative ways in which APIs can validate JWT access tokens, and the related use cases. The general pattern is to include additional key information in the JWT header, which the API can then read and supply to a JWT validation library.
The most common option for an API is to receive a JWT header with fields similar to the following:
JSON
The API then makes a request to the JWKS Endpoint of the Authorization Server over a trusted SSL connection, after which the key material received is trusted. The response provides JSON web keys (JWK) as described in , and the below example payload is for the widely used RS256 algorithm:
JSON
The API then looks up the key that matches the received kid
field and supplies it to the JWT library, which derives the public key from the n
(modulo) and e
(exponent) fields. The JWT library then uses the public key to verify the signature of the received JWT, to ensure it is cryptographically correct and has not been tampered with.
Once JWT validation is complete, the API caches the JWK and uses the cached value for future API requests whose JWT header has the same kid
field. This avoids excessive calls to the JWKS endpoint, which could otherwise lead to performance problems.
There are a couple of important scenarios where the standard option may not meet your requirements, and these are the most common:
Serverless / Cloud Native
In some API deployment scenarios a new instance of the API is spun up on every API request, or the API must remain stateless, so that calling the JWKS endpoint per request is prohibitive in performance terms
Financial Grade
It is possible for APIs to make additional trust checks against tokens using a Public Key Infrastructure (PKI), and in some setups this can ensure that trust brokering relationships between parties are verified
x5t
This is a SHA-1 hash of an X.509 certificate. This “thumbprint” of the certificate is why this header is referred to as an x5t for short.
x5t#s256
This is a SHA-256 hash of an X.509 certificate , and preferred over x5t since it is less likely to result in collisions.
x5c
This is also related to X.509 certificates, but the “C” in this header refers to the chain of certificates of the one used to sign the JWT.
jwk
A JSON web key provides token signing details and can also convey trust information via x5t, x5t#s256 and x5c fields.
JWTs can be validated by deploying one or more token signing certificates with the API, and then loading the certificate that matches the received x5t
or x5t#s256
value. In this setup the API has everything it needs locally, but the JWT is not really Self-contained since it does not contain the public key used for validation.
Once loaded, the certificate is then used to validate the JWT in the standard way. The API does not check in with the Authorization Server however, so is unable by default to detect JWTs signed with revoked token signing keys.
JSON
Using the x5c field to validate tokens verifies the full trust chain of the token using a Public Key Infrastructure, and can support sophisticated trust brokering setups. Private PKI setups are common these days, in which case the x5c verification proves that the JWT was signed with a private key issued by the company.
The PKI verification can include revocation checks to detect compromised token signing keys, so that those tokens are not accepted by the API. This can include the use of a Certificate Revocation List (CRL) or Online Certificate Status Protocol (OCSP) responder, to provide revoked key details.
This option is typically used in scenarios where the x5c certificate chain only contains certificate authorities and not the token signing certificate itself. The public key is then provided in the JWT header as a jwk
object, which can optionally include trust information in its x5c
field:
JSON
When relying on a JWK to verify a JWT you must ensure that it was not issued by a malicious party, and there are two alternative mechanisms here:
Using PKI to verify x5c certificates included with the JWK, which many companies consider more established, and which avoids the need for the API to make any https calls
When using Self-contained JWTs, an additional step is required, so that an attacker cannot create a JWT with their own certificate and send it to your API:
Verify the Trust Chain
Standard JWT Validation
Then verify the digital signature of the JWT, and also check the expiry, issuer and audience
The trust chain of the token signing certificate may look like this, where the CA certificates are long lived and can be deployed with your API, as a trust store
:
Signing Certificate
Used to digitally sign the JWT
6 months
Intermediate CA
A certificate authority used to issue the token signing certificate
10 years
Root CA
A certificate authority used to issue the intermediate certificate
10 years
In this type of setup the API will not have to be concerned with key management issues for 10 years or so. It also never has to make any outgoing calls, to get data from endpoints such as JWKS, Metadata or Webfinger endpoints. This provides a very simple, safe, and maintainable setup.
The high level steps to validate a Self-contained JWT should not require much code, since security libraries will do the main work, as in the following example Javascript code:
JAVASCRIPT
JWT validation libraries usually support supplying the token signing details in a variety of ways, so that validating a Self-contained JWT does not require much code:
As a JWKS download
API supplies a JWKS endpoint to the library
As a JWK
API supplies a jwk
object to the library
As a Certificate
API supplies the first certificate from the x5c
array to the library
Your Authorization Server should enable you to include additional fields so that token signing and trust details are made available in a Self-contained manner. As an example, the Curity Identity Server enables you to configure one or more , where these options can be activated. In the following sections we will drill into how the following fields are used when validating JWTs:
The x5c field can be included in the JWT header, to provide a Self-contained JWT with token signing certificate details. The format of this field is described in detail in , and it can optionally include a full trust chain, where the token signing certificate itself is the first entry:
Using , to verify that the JWT's iss
claim maps to an https URL whose certificate chain the API trusts
Ensure that the received token signing public key is provided by a trusted issuer, as detailed in
Source: