A closer look at key rotation policies & OIDC

Consider this familiar scenario from the internet. If we want to create an account or perform an operation on some website, we often come across social login buttons which enable us to login through well-known social network platforms and gain access to the website’s services.
It turns out that this capability is typically performed using something called JSON Web Tokens or JWTs for short. JWTs consist of 3 parts:
- Header — Containing all the necessary metadata like which cryptography algorithms are used, and a signing key ID identifying who digitally signed the JWT.
- Body — Containing all the custom data which is needed by the 3rd party from the social login service provider like Facebook and Google. They are more colloquially called “OIDC providers”, named after the standardized approach for using JWTs in this way.
- Signature — Containing all the vital information needed for validating whether or not the token is coming from a genuine source or forged at any point, including in between the transfer.
As a core member of a team developing an OIDC provider at DLT Labs, I have been continuously exploring OIDC and its related underlying technologies.
So, let me take you back to where it all began.
In the past decade, it is difficult to even imagine that such a technology could even exist. At the time, many websites directly asked you about your social login ID as well as for the password promising you to collect some of your information and keeping your privacy safe.
It was the time when only HTTP protocol existed. After a couple of years, OAuth 2.0 protocol was born that let a user registered on a website use services from other websites for which user has been granted permission, without sharing credentials like passwords.
This is known as authorization. Authorization had limitations, however, including that it cannot be used to validate or obtain the identity of the user. For overcoming this limitation, another standard, called OIDC, short for OpenID Connect, came into the picture, that was built on top of OAuth 2.0.
Since it was built on OAuth 2.0, it could still provide authorization, but it additionally could be used to obtain the user’s identity. This is known as authentication.
How does OIDC work?
OIDC uses a public key cryptography mechanism.
A private key is used by the OIDC provider to sign the JWT Token and it can be verified by a 3rd party using the public keys published on the OIDC provider’s well-known URL.
These keys form the basis of security between the parties. For security to be maintained, this is required to keep the private keys protected from any cyber-attacks.
One of the best practices that has been identified to secure the keys from being compromised is known as key rollover or key rotation. In this approach, we discard current keys and generate a new pair of keys to be used for signing and verifying the tokens. Let’s explore this approach in more detail.
Why do we need key rotation?
Data is a highly valued asset in the modern world. Unfortunately, the asymmetric cryptography mentioned earlier can in theory be defeated given enough computation power.
Since computation power has increased a lot in the past few years, security systems must take whatever steps they can to avoid the unwanted consequences of data being exposed or maliciously altered.
One thing that reduces the computation power needed by attackers is key reuse. We tend to use cryptography a lot while designing any security system but often tend to forget that the using the same old keys too frequently can allow hackers to succeed in their cryptanalysis resulting in the understanding of encoding and decoding patterns and, hence, putting all the vital information at risk.
In order to ensure the security of public and private key pairs from the hands of hackers, National Institute of Standards and Technology (NIST) proposes that one should rotate the keys after a certain period.
The previous keys must be discarded, and newly generated keys must be used for further cryptographic operations. According to NIST guidelines, both keys must be rotated at least once every two years.
How do we achieve key rotation?
Different OIDC providerers, like Okta, Google, Facebook, etc, have come up with different key rotation approaches. Some differ in the frequency in which they perform the rotation policy while others differ in the way they implement it.
All the public keys are published by the OIDC provider on a /certs or/keys endpoint over the web. The endpoint returns an object, known as a JSON Web Key Set, or JWKS which contains several JSON Web Keys, commonly known as JWK. These are used while verifying the JSON Web token signed with its corresponding private key. This object contains a key named keys and its value contains an array of JWKs as depicted by the screenshot below:

In order to rotate the keys, we need to maintain a well-defined sequence of the JWK keys array in the format that the newly generated keys are pushed at the end as well as the expired keys are popped out from the top, following a FIFO (first in, first out) structure.

The typical key rotation policy avoids a potential issue with clients sending the JWTs signed with the previously issued keys until the client refreshes the keys in its cache. So, in order to keep the client logged in with the previous key, we let the client perform actions with its previous key without being unauthorized.
So, we need to keep both keys (previous and current) valid for a certain period of time — just enough to provide room for clients to update their local caches — before the tokens are fully expired. This is based on an attribute called exp claim in the token.
A typical key rollover policy works like this:

The following steps need to be followed in order to let the client perform the actions smoothly after key rollover:
- Client sends the request to authorization server and includes its JWT token in each request.
- Authorization server tries to verify the token with the current key:
- If token is verified with the current key, the authorization server processes the necessary follow up tasks.
- If token is verified with the most recent previous key, the authorization server processes the necessary follow up tasks and issues a fresh token, digitally signed using the current key.
- Else, the authorization server sends back an error refusing the token.
An OpenID certified library called node-oidc-provider by Panva (Filip Skokan, an open source software developer not affiliated with DLT Labs) also recommends the following actions be done while performing signing key rotation:
1. Push new keys at the very end of the “keys” array in your JWKS, this means the keys will become available for verification should they be encountered but not yet used for signing.
2. Reload all your processes.
3. Move your new key to the very front of the “keys” array in your JWKS, this means the key will be used for signing after reloading.
4. Reload all your processes.
Moreover, according to the Security giant Auth0:
You can cache your signing keys to improve application performance … but you will want to make sure that if decoding a token fails, you invalidate the cache and retrieve new signing keys before trying only one more time.
BrockAllen and cursorblog specify to keep the previous key in the /certs or /keys endpoint for a certain period of time until the consumer updates its cache to the new signing key, allowing the previous key to be valid for a certain period of time, based on the expiry of the token issued.
OpenID certified provider library IdentityServer has mentioned the rollover of signing keys in its documentation. It states that a rollover typically works like this:
1. We request/create new key material.
2. Then we publish the new validation key in addition to the current one.
3. All clients and APIs now have a chance to learn about the new key the next time they update their local copy of the discovery document.
4. After a certain amount of time (e.g. 24h) all clients and APIs should now accept both the old and the new key material.
5. Keep the old key material around for as long as you like, maybe you have long-lived tokens that need validation.
6. Retire the old key material when it is not used anymore.
7. All clients and APIs will “forget” the old key next time they update their local copy of the discovery document.
This requires that clients and APIs use the discovery document, and also have a feature to periodically refresh their configuration.
Conclusion
We have learned the importance of key rollover policy and some of the ways in which it can be achieved. In most of the cases, we need to keep both keys valid until it is guaranteed that the previous key signed token will no more be valid.
Thank you for reading the article. Hope it helped you get a clear picture of key rotation policy.
Author — Shubh Saxena, DLT Labs™
About the Author: Shubh is our trainee software engineer. He is associated with the core development of identity provider at DLT Labs. He is deeply interested in blockchain and machine learning.
OpenID is a trademark (registered in numerous countries) of the OpenID Foundation. Auth0 is a trademark of Auth0, Inc.. Okta is a trademark of Okta, Inc.. Google is a trademark of Google, LLC. Facebook is a trademark of Facebook, Inc.. DLT Labs is a trademark of DLT Global, Inc..

References
https://developer.okta.com/docs/concepts/key-rotation/#key-rotation
https://github.com/panva/node-oidc-provider/blob/master/docs/README.md#jwks
https://brockallen.com/2019/08/09/identityserver-and-signing-key-rotation/
https://cursorblog.com/managing-a-secure-json-web-token-implementation/
http://docs.identityserver.io/en/latest/topics/crypto.html#signing-key-rollover
https://openid.net/specs/openid-connect-federation-1_0.html#rfc.section.8.1
