# `ConduitMcp.OAuth.KeyProvider.JWKS`
[🔗](https://github.com/nyo16/conduit_mcp/blob/v0.10.1/lib/conduit_mcp/oauth/key_provider/jwks.ex#L2)

JWKS key provider that fetches keys from an HTTP endpoint with ETS caching.

Fetches JSON Web Key Sets from the authorization server's JWKS URI,
caches them in ETS, and auto-refreshes on cache miss or expiration.

## Configuration

    auth: [
      strategy: :oauth,
      key_provider: {ConduitMcp.OAuth.KeyProvider.JWKS,
        jwks_uri: "https://auth.example.com/.well-known/jwks.json",
        cache_ttl: :timer.hours(1)}    # default: 1 hour
    ]

The `jwks_uri` must use `https`. For local development against a
plain-HTTP authorization server, set `allow_insecure_jwks: true` in the
provider config.

Fetches use conservative HTTP settings: redirects are not followed,
requests time out (5s connect / 10s receive), and responses are capped
at 1MB. If a refresh fails and previously fetched keys are still cached,
those stale keys are served (with a logged warning) so a transient
authorization-server outage does not hard-fail all authentication —
bounded by `:stale_max_age` (default 24 hours), after which the provider
fails closed so revoked keys cannot validate tokens indefinitely.

## Security considerations

**The `jwks_uri` must be trusted operator config — never client-derived.**
Fetches are hardened against SSRF abuse (`https`-only unless
`allow_insecure_jwks`, redirects disabled, 1MB body cap), but the URI
*itself* is not range-checked: a `jwks_uri` pointing at a private or
link-local address — e.g. the cloud metadata endpoint
`http(s)://169.254.169.254/...` — **is fetched, not rejected**. Set
`jwks_uri` from a configuration source you control. If it must come from a
less-trusted source, restrict outbound egress at the network layer (the
library deliberately does not block private ranges, since for most
deployments the JWKS endpoint *is* an internal/private host).

**Revocation lag during an outage.** While the JWKS endpoint is
unreachable, cached keys keep validating tokens until `:stale_max_age`
(default 24h), then the provider fails closed. The trade-off: a key
revoked *during* an outage can still validate tokens for up to
`:stale_max_age`. Lower it if your threat model needs faster revocation;
raise it to tolerate longer authorization-server outages.

## Requirements

Requires the `req` package. Use `0.6.1` or newer: earlier versions carry
advisories this provider can reach, including unbounded decompression driven
by the response's content-type (GHSA — Req `< 0.6.1`). The 1MB cap below is
applied to the *decoded* body, so it does not protect against a compression
bomb on its own.

    {:req, "~> 0.6"}

---

*Consult [api-reference.md](api-reference.md) for complete listing*
