Module oauth2

Module oauth2 

Source
Expand description

OAuth2 client-credentials proxying (DW-035, feature analysis 4.6).

The gateway acts as an OAuth2 client itself: for an upstream with an crate::config::OAuth2ClientCredentials block, it obtains an access token from an external token endpoint using the client-credentials grant (RFC 6749 section 4.4) and forwards that token to the upstream as Authorization: Bearer <token> (replacing any client-supplied Authorization header — the upstream sees the gateway’s token, not the client’s). This is for service-to-service calls where the gateway authenticates to the upstream with a token it obtains from an OAuth2 token endpoint.

§Flow

  1. Before forwarding a request to an upstream with oauth2_client_credentials configured, the gateway checks its token cache (per upstream, keyed by upstream name on the dataplane) for a valid token.
  2. If no valid token, it POSTs to the token endpoint with grant_type=client_credentials, the client_id and client_secret as HTTP Basic auth (RFC 6749 section 2.3.1), and scope (space-joined) when configured.
  3. The response ({access_token, token_type, expires_in, scope}) is cached with a TTL of min(expires_in - skew, token_cache_ttl_s) (or just expires_in - skew when no override is set). The skew (60 s) avoids using a token that expires while an in-flight request is still streaming.
  4. The gateway adds Authorization: Bearer <token> to the upstream request, REPLACING any existing Authorization header from the client.

§Caching

The cache is a Mutex<HashMap<UpstreamName, CachedToken>> on the dataplane. Token refresh is LAZY (on the first request after expiry) — no background refresh task. A token is considered valid while Instant::now() < expires_at; an expired entry is overwritten by the next fetch. Concurrent fetches for the same upstream serialize on a per-upstream tokio::Mutex so a token-endpoint fetch-storm cannot be driven by concurrent requests (the JWKS refresh-lock precedent).

§mTLS to the token endpoint

An optional mtls block configures a client certificate for the TLS handshake to the token endpoint itself (RFC 8705 tls_client_auth). The token endpoint’s SERVER certificate is verified against the webpki public roots by default; a private-CA token endpoint is not supported in this edition (the trusted_ca_file for the token endpoint would be a separate config field; deferred until an operator asks for it).

§Error posture

A token-endpoint failure (network error, non-2xx response, malformed body) surfaces to the client as 502 oauth2_token_unavailable — the gateway cannot authenticate to the upstream and refuses to forward without a token (never proxying unauthenticated). The error envelope never leaks the token endpoint’s response body or headers.

Structs§

OAuth2Client
One upstream’s OAuth2 client-credentials configuration at runtime: the resolved config plus a per-upstream HTTP client and a fetch serialization lock. The token cache lives on the dataplane (OAuth2TokenCache) so a config reload reuses cached tokens.
OAuth2TokenCache
Per-upstream OAuth2 token cache (DW-035): lives on the dataplane so a config reload reuses cached tokens (the JWKS cache precedent). Entries are keyed by upstream name; each holds the cached token and its skew-adjusted expiry. Refresh is lazy (on the first request after expiry) — no background task.

Enums§

OAuth2Error
Error acquiring a token (DW-035). All variants surface to the client as 502 oauth2_token_unavailable; the Display text is logged, not sent to the client (the envelope never leaks upstream internals).