Skip to main content

OAuthConfig

Struct OAuthConfig 

Source
#[non_exhaustive]
pub struct OAuthConfig {
Show 20 fields pub issuer: String, pub audience: String, pub jwks_uri: String, pub scopes: Vec<ScopeMapping>, pub role_claim: Option<String>, pub role_mappings: Vec<RoleMapping>, pub jwks_cache_ttl: String, pub proxy: Option<OAuthProxyConfig>, pub token_exchange: Option<TokenExchangeConfig>, pub ca_cert_path: Option<PathBuf>, pub allow_http_oauth_urls: bool, pub ssrf_allowlist: Option<OAuthSsrfAllowlist>, pub max_jwks_keys: usize, pub allowed_algorithms: Option<Vec<String>>, pub authorization_servers: Option<Vec<String>>, pub authorization_server_metadata_issuer: Option<String>, pub require_subject: bool, pub strict_audience_validation: Option<bool>, pub audience_validation_mode: Option<AudienceValidationMode>, pub jwks_max_response_bytes: u64,
}
Expand description

OAuth 2.1 JWT configuration.

Fields (Non-exhaustive)§

This struct is marked as non-exhaustive
Non-exhaustive structs could have additional fields added in future. Therefore, non-exhaustive structs cannot be constructed in external crates using the traditional Struct { .. } syntax; cannot be matched against without a wildcard ..; and struct update syntax will not work.
§issuer: String

Token issuer (iss claim). Must match exactly.

#[serde(default)] so a partially-specified [oauth] table — one that carries only role_claim/role_mappings, with the URL and audience fields supplied by a downstream env-override layer applied after TOML parsing — still deserializes. An empty value is rejected at OAuthConfig::validate time (parse-don’t-validate): the HTTPS URL check fails on an empty string.

§audience: String

Expected audience (aud claim). Must match exactly.

Defaulted like OAuthConfig::issuer. Unlike the URL fields it is not a URL, so OAuthConfig::validate guards it with an explicit non-empty check.

§jwks_uri: String

JWKS endpoint URL (e.g. https://auth.example.com/.well-known/jwks.json).

Defaulted like OAuthConfig::issuer; an empty value is rejected by the HTTPS URL check in OAuthConfig::validate.

§scopes: Vec<ScopeMapping>

Scope-to-role mappings. First matching scope wins. Used when role_claim is absent (default behavior).

§role_claim: Option<String>

JWT claim path to extract roles from (dot-notation for nested claims).

Examples: "scope" (default), "roles", "realm_access.roles". When set, the claim value is matched against role_mappings instead of scopes. Supports both space-separated strings and JSON arrays.

§role_mappings: Vec<RoleMapping>

Claim-value-to-role mappings. Used when role_claim is set. First matching value wins.

§jwks_cache_ttl: String

How long to cache JWKS keys before re-fetching. Parsed as a humantime duration (e.g. “10m”, “1h”). Default: “10m”.

§proxy: Option<OAuthProxyConfig>

OAuth proxy configuration. When set, the server exposes /authorize, /token, and /register endpoints that proxy to the upstream identity provider (e.g. Keycloak).

§token_exchange: Option<TokenExchangeConfig>

Token exchange configuration (RFC 8693). When set, the server can exchange an inbound MCP-scoped access token for a downstream API-scoped access token via the authorization server’s token endpoint.

§ca_cert_path: Option<PathBuf>

Optional path to a PEM CA bundle for OAuth-bound HTTP traffic. Added to the system/built-in roots, not a replacement.

Scope (since 1.2.1). When the OauthHttpClient is constructed via OauthHttpClient::with_config (preferred), this CA bundle is honoured by every OAuth-bound HTTP request: the JWKS key fetch, token exchange, introspection, revocation, and the OAuth proxy handlers. Application crates may auto-populate this from their own configuration (e.g. an upstream-API CA path); any application-owned HTTP clients outside the kit must still configure their own CA trust separately. The deprecated OauthHttpClient::new no-arg constructor cannot honour this field – migrate to OauthHttpClient::with_config for full coverage.

§allow_http_oauth_urls: bool

Allow plain-HTTP (non-TLS) URLs for OAuth endpoints (jwks_uri, proxy.authorize_url, proxy.token_url, proxy.introspection_url, proxy.revocation_url, token_exchange.token_url).

Default: false. Strongly discouraged in production: a network-positioned attacker can MITM JWKS responses and substitute signing keys (forging arbitrary tokens), or MITM the token / proxy endpoints to steal credentials and codes. Enable only for development against a local IdP without TLS, ideally bound to 127.0.0.1.

Redirect handling when this flag is true: an HTTPS → HTTP downgrade is always rejected, but an HTTP → HTTP redirect is permitted (the target must still pass SSRF screening). When the flag is false, every non-HTTPS redirect target is rejected.

§ssrf_allowlist: Option<OAuthSsrfAllowlist>

Operator-trusted SSRF allowlist for OAuth/JWKS targets.

Default: None (fail-closed; current behavior preserved). When set, the listed hostnames and CIDR blocks may resolve into otherwise-blocked address ranges (RFC 1918, loopback, link-local, CGNAT, IPv6 unique-local, …). Cloud-metadata addresses remain unbypassable regardless of this setting – see OAuthSsrfAllowlist and SECURITY.md § “Operator allowlist”.

§max_jwks_keys: usize

Maximum number of keys accepted from a JWKS refresh response. Requests returning more keys than this are rejected fail-closed (cache remains empty / unchanged). Default: 256.

§allowed_algorithms: Option<Vec<String>>

Optional allowlist of accepted JWT signing algorithms.

Default None, which accepts the crate’s built-in set: RS256, RS384, RS512, ES256, ES384, PS256, PS384, PS512, EdDSA.

When set, it must be a non-empty subset of that built-in set; anything else fails OAuthConfig::validate. Names are matched case-insensitively. This knob can only ever NARROW the accepted algorithms – it cannot re-enable HS* or none, so an operator cannot use it to open an algorithm-confusion hole.

Use it to pin a deployment to exactly what its identity provider signs with, e.g. ["RS256"] for Microsoft Entra v2.0.

§authorization_servers: Option<Vec<String>>

Authorization servers advertised in RFC 9728 Protected Resource Metadata.

Default None = resolved from topology, which is the RFC-correct answer in both directions:

  • OAuthConfig::proxy configured -> this server’s public URL. The proxy really does mount /authorize, /token, /register, and /.well-known/oauth-authorization-server.
  • no proxy -> the upstream OAuthConfig::issuer. This process mounts no authorization-server endpoints, so advertising itself would send RFC 9728 discovery to a URL that returns 404.

Set this explicitly if your application mounts its own /authorize and /token through McpServerConfig::with_extra_router without configuring OAuthConfig::proxy — that server is the authorization server, and the crate cannot detect it. Set it to the server’s public URL.

Some(vec![]) omits authorization_servers from the document entirely, per RFC 9728 3.2 (zero-valued claims must be omitted).

§authorization_server_metadata_issuer: Option<String>

issuer published in the RFC 8414 Authorization Server Metadata document served by the built-in proxy.

Default None = this server’s own public URL, which is what RFC 8414 3.3 requires: the published issuer MUST be identical to the identifier the metadata URL was built from, and this document is served from the local origin. RFC 8414 6.2 additionally requires clients to reject a mismatch, so the previous behaviour (publishing the upstream issuer) was rejected outright by conformant clients.

Legacy opt-out. Set this to your upstream OAuthConfig::issuer to restore the pre-3.8 value. The one case that needs it: an upstream IdP that emits RFC 9207 iss in the authorization response and clients that validate it. The proxy does not own the front channel — /authorize redirects to the upstream, which redirects straight back to the client’s redirect_uri without passing through this process — so it cannot reconcile a local issuer with an upstream-stamped iss.

Token validation is unaffected either way: inbound JWT iss claims are always checked against OAuthConfig::issuer.

§require_subject: bool

Require the JWT sub (subject) claim. Default: false (current behavior). When true, a token without sub is rejected. Leave false for OAuth client-credentials / machine-to-machine tokens, which legitimately carry no subject.

§strict_audience_validation: Option<bool>
👎Deprecated since 1.7.0:

use audience_validation_mode instead; this field is consulted only when audience_validation_mode is None

Enforce strict audience validation using only the JWT aud claim.

Deprecated since 1.7.0. Use OAuthConfig::audience_validation_mode instead. Consulted only when OAuthConfig::audience_validation_mode is None: Some(true) resolves to AudienceValidationMode::Strict, Some(false) resolves to AudienceValidationMode::Warn, and None (the default) resolves to AudienceValidationMode::Strict — the secure default that rejects azp-only audience matches.

§audience_validation_mode: Option<AudienceValidationMode>

How the resource server treats azp when validating JWT audience.

When None (default), resolution falls back to the deprecated OAuthConfig::strict_audience_validation flag: Some(true)AudienceValidationMode::Strict, Some(false)AudienceValidationMode::Warn, and NoneAudienceValidationMode::Strict (the secure default). Set this field explicitly to make the policy unambiguous.

§jwks_max_response_bytes: u64

Maximum size of a JWKS HTTP response body in bytes. Responses exceeding this cap are refused and logged; the cache remains empty / unchanged. Default: 1 MiB.

Implementations§

Source§

impl OAuthConfig

Source

pub fn effective_audience_validation_mode(&self) -> AudienceValidationMode

Resolve the effective audience-validation policy.

Precedence: explicit audience_validation_mode overrides the legacy strict_audience_validation flag. When neither is set, the default is AudienceValidationMode::Strict (secure default; azp-only matches are rejected).

Source

pub fn builder( issuer: impl Into<String>, audience: impl Into<String>, jwks_uri: impl Into<String>, ) -> OAuthConfigBuilder

Start building an OAuthConfig with the three required fields.

All other fields default to the same values as OAuthConfig::default (empty scopes/role mappings, no proxy or token exchange, a JWKS cache TTL of 10m).

Source

pub fn validate(&self) -> Result<(), RmcpServerKitError>

Validate the URL fields against the HTTPS-only policy.

Each of jwks_uri, proxy.authorize_url, proxy.token_url, proxy.introspection_url, proxy.revocation_url, and token_exchange.token_url is parsed and its scheme checked.

Schemes other than https are rejected unless OAuthConfig::allow_http_oauth_urls is true, in which case http is also permitted (parse failures and other schemes are always rejected).

§Errors

Returns crate::error::RmcpServerKitError::Config when any field fails to parse or violates the scheme policy.

Trait Implementations§

Source§

impl Clone for OAuthConfig

Source§

fn clone(&self) -> OAuthConfig

Returns a duplicate of the value. Read more
1.0.0 (const: unstable) · Source§

fn clone_from(&mut self, source: &Self)

Performs copy-assignment from source. Read more
Source§

impl Debug for OAuthConfig

Source§

fn fmt(&self, f: &mut Formatter<'_>) -> Result

Formats the value using the given formatter. Read more
Source§

impl Default for OAuthConfig

Source§

fn default() -> Self

Returns the “default value” for a type. Read more
Source§

impl<'de> Deserialize<'de> for OAuthConfig

Source§

fn deserialize<__D>(__deserializer: __D) -> Result<Self, __D::Error>
where __D: Deserializer<'de>,

Deserialize this value from the given Serde deserializer. Read more

Auto Trait Implementations§

Blanket Implementations§

Source§

impl<T> Any for T
where T: 'static + ?Sized,

Source§

fn type_id(&self) -> TypeId

Gets the TypeId of self. Read more
Source§

impl<'a, T, E> AsTaggedExplicit<'a, E> for T
where T: 'a,

Source§

fn explicit(self, class: Class, tag: u32) -> TaggedParser<'a, Explicit, Self, E>

Source§

impl<'a, T, E> AsTaggedImplicit<'a, E> for T
where T: 'a,

Source§

fn implicit( self, class: Class, constructed: bool, tag: u32, ) -> TaggedParser<'a, Implicit, Self, E>

Source§

impl<T> Borrow<T> for T
where T: ?Sized,

Source§

fn borrow(&self) -> &T

Immutably borrows from an owned value. Read more
Source§

impl<T> BorrowMut<T> for T
where T: ?Sized,

Source§

fn borrow_mut(&mut self) -> &mut T

Mutably borrows from an owned value. Read more
Source§

impl<ST, DT> CastableFrom<ST, Initialized, Initialized> for DT
where ST: ?Sized, DT: ?Sized,

Source§

impl<ST, DT> CastableFrom<ST, Uninit, Uninit> for DT
where ST: ?Sized, DT: ?Sized,

Source§

impl<T> CloneToUninit for T
where T: Clone,

Source§

unsafe fn clone_to_uninit(&self, dest: *mut u8)

🔬This is a nightly-only experimental API. (clone_to_uninit)
Performs copy-assignment from self to dest. Read more
Source§

impl<T> DeserializeOwned for T
where T: for<'de> Deserialize<'de>,

Source§

impl<T> DynClone for T
where T: Clone,

Source§

fn __clone_box(&self, _: Private) -> *mut ()

Source§

impl<T> From<T> for T

Source§

fn from(t: T) -> T

Returns the argument unchanged.

Source§

impl<T> FromRef<T> for T
where T: Clone,

Source§

fn from_ref(input: &T) -> T

Converts to this type from a reference to the input type.
Source§

impl<A, B, T> HttpServerConnExec<A, B> for T
where B: Body,

Source§

impl<T> Instrument for T

Source§

fn instrument(self, span: Span) -> Instrumented<Self>

Instruments this type with the provided Span, returning an Instrumented wrapper. Read more
Source§

fn in_current_span(self) -> Instrumented<Self>

Instruments this type with the current Span, returning an Instrumented wrapper. Read more
Source§

impl<T, U> Into<U> for T
where U: From<T>,

Source§

fn into(self) -> U

Calls U::from(self).

That is, this conversion is whatever the implementation of From<T> for U chooses to do.

Source§

impl<T> PolicyExt for T
where T: ?Sized,

Source§

fn and<P, B, E>(self, other: P) -> And<T, P>
where T: Sized + Policy<B, E>, P: Policy<B, E>,

Create a new Policy that returns Action::Follow only if self and other return Action::Follow. Read more
Source§

fn or<P, B, E>(self, other: P) -> Or<T, P>
where T: Sized + Policy<B, E>, P: Policy<B, E>,

Create a new Policy that returns Action::Follow if either self or other returns Action::Follow. Read more
Source§

impl<T> Read<Exclusive, BecauseExclusive> for T
where T: ?Sized,

Source§

impl<T> Same for T

Source§

type Output = T

Should always be Self
Source§

impl<T> ToOwned for T
where T: Clone,

Source§

type Owned = T

The resulting type after obtaining ownership.
Source§

fn to_owned(&self) -> T

Creates owned data from borrowed data, usually by cloning. Read more
Source§

fn clone_into(&self, target: &mut T)

Uses borrowed data to replace owned data, usually by cloning. Read more
Source§

impl<T, U> TryFrom<U> for T
where U: Into<T>,

Source§

type Error = !

The type returned in the event of a conversion error.
Source§

fn try_from(value: U) -> Result<T, <T as TryFrom<U>>::Error>

Performs the conversion.
Source§

impl<T, U> TryInto<U> for T
where U: TryFrom<T>,

Source§

type Error = <U as TryFrom<T>>::Error

The type returned in the event of a conversion error.
Source§

fn try_into(self) -> Result<U, <U as TryFrom<T>>::Error>

Performs the conversion.
Source§

impl<V, T> VZip<V> for T
where V: MultiLane<T>,

Source§

fn vzip(self) -> V

Source§

impl<T> WithSubscriber for T

Source§

fn with_subscriber<S>(self, subscriber: S) -> WithDispatch<Self>
where S: Into<Dispatch>,

Attaches the provided Subscriber to this type, returning a WithDispatch wrapper. Read more
Source§

fn with_current_subscriber(self) -> WithDispatch<Self>

Attaches the current default Subscriber to this type, returning a WithDispatch wrapper. Read more