diff --git a/docs/router/authentication-and-authorization.mdx b/docs/router/authentication-and-authorization.mdx
index 495c11c3..b472bf56 100644
--- a/docs/router/authentication-and-authorization.mdx
+++ b/docs/router/authentication-and-authorization.mdx
@@ -26,6 +26,11 @@ In the current router version, the configuration and behavior of authentication
- url: https://example.com/.well-known/jwks.json
refresh_interval: 1m
algorithms: ["RS256"]
+ refresh_unknown_kid:
+ enabled: true
+ max_wait: 2m
+ interval: 30s
+ burst: 5
- url: https://example2.com/.well-known/jwks.json
refresh_interval: 2m
# optional list of allowed algorithms per JWKS
@@ -89,3 +94,38 @@ Authentication information is also available to custom modules. See [Access Auth
### Forwarding authentication headers
By default, the router won't forward authentication headers to subgraphs, but if desired this can be configured using [Proxy capabilities](/router/proxy-capabilities).
+
+
+### Refreshing Unknown KIDs on Demand
+
+When `refresh_unknown_kid.enabled` is set to `true`, the router will automatically attempt to refresh the JWKS (fetch updated keys) whenever it encounters a valid token with an unknown KID (Key ID). This is useful when key rotation has occurred but the router hasn't picked up the new keys in its regular refresh cycle.
+
+To prevent overwhelming the JWKS endpoint, this feature includes rate limiting controlled by the following parameters:
+- `burst`: Maximum number of refreshes allowed without waiting. Internally, the router keeps a counter of available burst tokens. Each time the `interval` elapses, one token is replenished, up to the `burst` limit.
+- `interval`: The time that must elapse between replenishing burst tokens, until the `burst` limit is reached.
+- `max_wait`: Maximum time a refresh is allowed to wait. If the computed wait would exceed this value, the request is rejected immediately with a 401 Unauthorized status instead of waiting.
+
+#### Rate Limiting Example
+
+Let's examine how rate limiting works with these settings:
+```yaml
+refresh_unknown_kid:
+ enabled: true
+ burst: 1
+ interval: 30s
+ max_wait: 110s
+```
+
+
+If we send 6 simultaneous requests with unknown KIDs:
+1. First request: JWKS refreshed immediately; 1 burst token is consumed.
+2. Second request: Waits for 30s (interval × 1); a token is replenished after 30s.
+3. Third request: Waits for 60s (interval × 2); a token is replenished after another 30s.
+4. Fourth request: Waits for 90s (interval × 3); a token is replenished after another 30s.
+5. Fifth request: Fails immediately (would require 120s wait > max_wait) with 401 Unauthorized.
+6. Sixth request: Fails immediately (would require 150s wait > max_wait) with 401 Unauthorized.
+
+The 2nd, 3rd and 4th requests are rate-limited because the burst capacity is set to 1. After the first request passes, the number of available burst tokens is 0 and subsequent requests must wait until the `interval` elapses. If `burst` were set to 2, the second request would also pass immediately.
+
+The `max_wait` setting prevents excessive wait times. In this example, since the 5th and 6th requests would require waiting longer than the configured `max_wait` of 110s, they immediately return with a 401 Unauthorized status instead of attempting to refresh.
+
diff --git a/docs/router/configuration.mdx b/docs/router/configuration.mdx
index 2eba810c..d3f8436b 100644
--- a/docs/router/configuration.mdx
+++ b/docs/router/configuration.mdx
@@ -1425,9 +1425,13 @@ This is useful when you want to connect to a JWKS endpoint
| YAML | Required | Description | Default Value |
| --------------------------------------------------------------------------- | ---------------------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | -----------------|
-| url | | The URL of the JWKs. The JWKs are used to verify the JWT (JSON Web Token). The URL is specified as a string with the format 'scheme://host:port'. | |
-| refresh_interval | | The interval at which the JWKs are refreshed. The period is specified as a string with a number and a unit, e.g. 10ms, 1s, 1m, 1h. The supported units are 'ms', 's', 'm', 'h'. | 1m |
+| url | | The URL of the JWKs. The JWKs are used to verify the JWT (JSON Web Token). The URL is specified as a string with the format 'scheme://host:port'. | |
+| refresh_interval | | The interval at which the JWKs are refreshed. The period is specified as a string with a number and a unit, e.g. 10ms, 1s, 1m, 1h. The supported units are 'ms', 's', 'm', 'h'. | 1m |
| algorithms | | The allowed algorithms for the keys that are retrieved from the JWKs. An empty list means that all algorithms are allowed. The following algorithms are supported "RS256", "RS384", "RS512", "ES256", "ES384", "ES512", "PS256", "PS384", "PS512", "EdDSA" | [] (all allowed) |
+| refresh_unknown_kid.enabled | | Enable automatic JWKS refresh when encountering a valid token with an unknown KID (Key ID). When enabled, the router will fetch updated keys to find the matching KID. | false |
+| refresh_unknown_kid.max_wait | | Maximum time a refresh is allowed to wait. If the computed wait would exceed this value, the request fails immediately with 401 Unauthorized instead of waiting. | 2m |
+| refresh_unknown_kid.interval | | Time between replenishing burst tokens. With burst=1, each subsequent request within the interval must wait for (interval × attempt number). | 30s |
+| refresh_unknown_kid.burst | | Maximum number of refreshes allowed without waiting. Prevents overloading the JWKS endpoint; beyond this, requests wait until the interval elapses or fail due to max_wait. | 2 |
#### Secret
This is useful when you have a symmetric key that you cannot expose through a JWKS endpoint, you can use the secret based configuration
@@ -1472,10 +1476,20 @@ authentication:
- url: "https://example.com/.well-known/jwks.json"
refresh_interval: 1m
# Leaving algorithms empty will allow all supported algorithms from the config docs
+ refresh_unknown_kid:
+ enabled: true
+ max_wait: 2m
+ interval: 30s
+ burst: 2
- url: "https://example2.com/.well-known/jwks.json"
refresh_interval: 2m
# optional list of allowed algorithms per JWKS
algorithms: ["RS256", "EdDSA", "HS512"]
+ refresh_unknown_kid:
+ enabled: false # These are defaults
+ max_wait: 2m
+ interval: 30s
+ burst: 2
header_name: Authorization # This is the default value
header_value_prefix: Bearer # This is the default value
header_sources: