I am looking for some guidance with configuring owin middleware bearer token authentication to support Open Id Connect key rotation.
The Opend Id Connect spec says the following about key rotation:
Rotation of signing keys can be accomplished with the following approach. The signer publishes its keys in a JWK Set at its jwks_uri location and includes the kid of the signing key in the JOSE Header of each message to indicate to the verifier which key is to be used to validate the signature. Keys can be rolled over by periodically adding new keys to the JWK Set at the jwks_uri location. The signer can begin using a new key at its discretion and signals the change to the verifier using the kid value. The verifier knows to go back to the jwks_uri location to re-retrieve the keys when it sees an unfamiliar kid value.
The most similar question I could find on this subject is this: SecurityTokenSignatureKeyNotFoundException in OWIN OpenID Connect middleware connecting to Google
The solution doesn't quite work as you will get errors between the time a new private key is issued and the time a client refreshes their cache of public keys.
So I want to configure the client to download the missing public JWK key whenever it finds a valid, correctly signed, non-expired JWT token that has a kid that is not cache locally.
I am current using IdentityServer3.AccessTokenValidation but the client does not download a new key when it recevies a token with a kid it doesn't recognise.
I have had a quick look at Microsoft.Owin.Security.Jwt -> UseJwtBearerAuthentication And also Microsoft.Owin.Security.OpenIdConnect -> UseOpenIdConnectAuthentication But I didn't get too far.
I'm looking for some direction to extend / configure any of the above packages to support the key rotation.
I figured it out using the system.IdentityModel.Tokens.Jwt library. I had a lot of trouble with versioning so I've included the nuget packages that I ended up using. I had lots of issues with Microsoft.IdentityModel.Tokens.Jwt so I abandoned that approach. Anyway here are the packages:
And here is the code. The way it works is by setting a custom key resolver. This key resolver gets called everytime a token is passed in. When we get a kid cache miss we make a new request to the Token Service to download the latest set of keys. Initially I thought of checking various parts of the key first (i.e. non expired / valid issuer) but then decided against this because if we cannot confirm that the token is signed correctly then adding those checks is pointless. An attacker could set them to whatever they want.
Some throttling around the getting of the keys would make sense to stop a malicious user forcing many roundtrips to the token service.