JSON Web Tokens (JWT) use digital signatures to establish the authenticity of the data they contain, as well as authenticating the identity of the signer. A valid signature check ensures that any party can rely on the contents and the signatory of the JWT. This is typically accomplished by using an asymmetric signing algorithm such as RS-256 (RSA + SHA256 hash). The "asymmetry" is where the private key of a key pair is used to sign a piece of information, and the public key is used to verify that it was signed by a specific private key (without actually having the key).
Akamai's JWT validation in API Gateway also relies on digital signature. The public key for a token is held on each Edge server to enable signature validation. Until now, customers could upload both a primary and secondary public key by using the Luna portal or an administrative API. This allowed key rotation as needed, but was a manual and somewhat clunky process.
To make rotation of signing keys seamless, we have released an enhancement to our ability to hold public keys at the Edge. JSON Web Key Set, or JWKS, is an IETF standard (RFC-7517) which allows Gateway customers to rotate signature keys quickly and routinely. JWKS provides several benefits when implementing JWT's:
- If keys must be rotated on a scheduled basis, an application can grab the new certificates dynamically
- In the rare event of a security problem where forced rotation of keys is necessary (ex: current keys are compromised or new security standards must be enforced).
- Reduces interruptions and downtime when managing keys, so this is one less problem to worry about
At its most basic level, JWKS is a set of public keys that can be used to verify any JWT issued by a Gateway customer. It is fundamentally a JSON object that acts as a container for a list of public key elements in array form. Let's decompose a sample JWKS file (see screenshot below).
Each element in the array represents a specific cryptographic public key, called a JWK (JSON Web Key) that can be used to validate the signature of a signed JWT. It also contains other related properties as name/value pairs.
These are what the individual elements in the JWK represent:
These individual elements are made available at what is known as a JWKS _URI. This is a read-only, open endpoint that creates a standardized means for an application to fetch and validate a specific key from the array of JSON objects. A full JWKS_URI might look like this:
The path https://<your_domain>/.well-known/jwks.json is the default path from which Edge servers will request a JWKS file using the Transport Layer Security (TLS) protocol. The ".well-known" prefix used here provides a commonly-accepted location for resources of this type and helps avoid collisions between resources, but the endpoint can vary based on your requirements. For more details on the "well-known" prefix, please see RFC 5785. Note that Akamai can also cache calls to JWKS_URI to avoid overwhelming the endpoint.
To enable rotation of signing keys using JWKS in API Gateway, login to the Luna GUI. Next, browse to a version of your API, and select JSON Web Tokens (JWT) from the sidebar. Once there, you will see the screen below:
To use a JWKS instead of static RSA Public keys:
- Select "JWKS_URI" as the Public key format
- Click "Choose file" to upload a certificate chain.
- Here you can optionally specify a list of allowed JWK hosts and
- the max-age of the public key.
You must publish your JWKS at a JWKS_URI location, and include the kid (Key ID) of the signing key in the JOSE Header of each message. This indicates to the verifier (usually an application) which key is to be used to validate the signature.
The verifier gets the JWT token and decodes it, extracting the "jku"' claim from the token header. It then validates that the hostname in the jku matches the hostname that was specified in the JWKS_URI. Akamai then fetches the JWKS content from the location specified by the jku. Next, the verifier decodes the JWKS object, checks that it is a properly-formatted JSON object, and uses the 'kid' field to find the matching key in the keyset. The verifier can then construct a public key and perform verification on the matched key.
Keys may be updated at any time simply by adding new key entries to the JWKS file at the JWKS_URI location. This will automatically signal a change to a verifier when it goes back to the JWKS_URI location to retrieve the keys, and encounters an unfamiliar, new key value.