There is a feature that may be help you with this, it’s a bit of a bastardisation of the JWK format, but it allows you to specify multiple secrets for a single API Definition, so that you can target them using a kid
. In this case the kid
refers to a Secret ID (the key in this sense being the RSA key).
This isn’t currently documented because it doesn’t fully follow the JWK spec. However it works just fine for use cases where you have one API and multiple IDPs with different RSA Public keys and you want to validate them separately but manage them centrally.
With the JWK method, Tyk will:
- Identify the KID from the inbound JWT
- Pull the JWK file from the JWK service provider
- Check the KID against those listed in the JWK
- If the KID exists in the JWK key-list, it will try to verify the signature of the JWT with the first key in the JWK keys list
- If the JWK is valid, extract the
sub
andpolicy_id
claims to generate a virtual token based on the policy, tied to the bearer
This flow describes what you are trying to achieve: Multiple Secrets → One API → Multiple Policies → Virtual token
To get this to work, you create a document on a server that only Tyk Gateway can see and should use HTTPS, this will be a public-key source, let’s say we call the file idp_jwks.json
and this file is hosted on https://my-internal-server.com/idp_jwks.json
:
idp_jwks.json:
{
"keys": [{
"alg": "RS256",
"kty": "RSA",
"use": "sig",
"x5c": ["LS0tLS1CRUdJTiBQVUJMSUMgS0VZLS0tLS0NCk1JR2ZNQTBHQ1NxR1NJYjNEUUVCQVFVQUE0R05BRENCaVFLQmdRQ3FHS3VrTzFEZTd6aFpqNitIMHF0alRrVnh3VENwdktlNGVDWjANCkZQcXJpMGNiMkpaZlhKL0RnWVNGNnZVcHdtSkc4d1ZRWktqZUdjakRPTDVVbHN1dXNGbmNDeldCUTdSS05VU2VzbVFSTVNHa1ZiMS8NCjNqK3NrWjZVdFcrNXUwOWxITnNqNnRRNTFzMVNQckNCa2VkYk5mMFRwMEdiTUpEeVI0ZTlUMDRaWndJREFRQUINCi0tLS0tRU5EIFBVQkxJQyBLRVktLS0tLQ=="],
"kid": "12345",
},
{
"alg": "RS256",
"kty": "RSA",
"use": "sig",
"x5c": ["LS0tLS1CRUdJTiBQVUJMSUMgS0VZLS0tLS0NCk1JR2ZNQTBHQ1NxR1NJYjNEUUVCQVFVQUE0R05BRENCaVFLQmdRQ3FHS3VrTzFEZTd6aFpqNitIMHF0alRrVnh3VENwdktlNGVDWjANCkZQcXJpMGNiMkpaZlhKL0RnWVNGNnZVcHdtSkc4d1ZRWktqZUdjakRPTDVVbHN1dXNGbmNDeldCUTdSS05VU2VzbVFSTVNHa1ZiMS8NCjNqK3NrWjZVdFcrNXUwOWxITnNqNnRRNTFzMVNQckNCa2VkYk5mMFRwMEdiTUpEeVI0ZTlUMDRaWndJREFRQUINCi0tLS0tRU5EIFBVQkxJQyBLRVktLS0tLQ=="],
"kid": "9999999",
}]
}
As you can see this document contains a list of RSA Public keys (the key is in the x5c
property - this is not on-spec), these keys are a base64-encoded version of the PEM-encoded version of the RSA public key (if you decode it you’ll see a traditional public key ascii file format - this is where we also differ from the JWK spec). All these keys are delimited by their key ID.
Now when you set up your API that needs to validate multiple JWT sources (i.e. you may not want Auth0 providing the credentials for your internal app-to-app comms) then you have one key that is Auth0’s public key and another that is for your internal app-to-app stuff (in fact, you can have as many as you like).
In your Tyk API Definition, in the JWT secret field, instead of a public key, you just put our custom JWK URL:
https://my-internal-server.com/idp_jwks.json
Now when a JWT comes in, so long as the kid
matches one in the JWK file (this file is cached periodically to speed things up) it will validate and apply the policy specified in the policy ID field claim of the JWT so you can rate limit on a per-client, per-source basis.
With the above, this is possible:
- An API has a JWK instead of a single secret
- Each customer’s secret is set as a KID in the JWK, so you can extend this as you will, it will refresh over time (a hot reload should also force this)
- You create a few policies (e.g.
AppToApp
,CustomerTier1
,CustomerTier2
,CustomerTier3
andEnterprise
) - Depending on the IDP or source of the JWT, you set the appropriate
policy_id
as a claim in the JWT so that uers are rate limited differently depending on where they come from.
This functionality has been part of Tyk for a while, but isn’t documented because our JWK documents are non-spec and we do not follow the spec in full, e.g. we don’t check the key-type field, we assume the key type is the same as that of the API Definition.
Full compliance is in our OIDC middleware though - but that is fully compliant with the whole set of specs associated with OpenID Connect, and is totally separate from our custom JWT implementation (which offers a bit of flex). OIDC is available in nightlies and will be available as a full release in a few weeks.
I hope that helps!
M.