docs: clarify external OAuth consent mode (#4746)

This commit is contained in:
Jeremiah Lowin 2026-08-03 18:02:09 -04:00 committed by GitHub
commit d267792653
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
16 changed files with 49 additions and 32 deletions

View file

@ -315,8 +315,10 @@ auth = OAuthProxy(..., client_storage=MemoryStore())
**`"remember"` — silent consent on return:**
Users see the consent screen on first authorization; subsequent flows from the same browser for the same `(client_id, redirect_uri)` are silently approved via a signed cookie. Cross-site navigations (detected via `Sec-Fetch-Site`) fall back to the prompt. `Sec-Fetch-Site` is a browser-level heuristic rather than a protocol guarantee: an attacker who finds a way to initiate a non-cross-site navigation (XSS on a sibling origin, a same-site redirect chain, etc.) can reach the silent-consent path. `True` does not depend on this signal. See [Confused Deputy Attacks](#confused-deputy-attacks) for the underlying attack class.
**`"external"` — delegate to upstream:**
Skip the built-in consent page; consent is collected by the upstream IdP or a custom login page referenced via `upstream_authorization_endpoint`. No security warning is logged.
**`"external"` — externally managed:**
Follows the same authorization path as `False`: FastMCP skips its consent page and associated browser-binding protections, then redirects directly to the upstream provider. The difference is logging. `False` emits a security warning, while `"external"` suppresses that warning as an explicit acknowledgment that the operator is enforcing equivalent consent and transaction-binding protections elsewhere. FastMCP does not provide or verify those external protections.
Ordinary upstream OAuth consent is generally not equivalent. It typically authorizes FastMCP's shared upstream application without identifying the downstream MCP client or binding approval to that client's transaction. Use `"external"` only when your surrounding authorization system supplies those protections.
**`False` — disable entirely:**
Authorization proceeds directly to the upstream provider without any consent UI. Logs a security warning. Only for local development or testing.
@ -336,7 +338,7 @@ auth = OAuthProxy(..., client_storage=MemoryStore())
```
<Warning>
Disabling consent removes an important security layer. Only disable for local development or testing environments where you fully control all connecting clients.
Both `False` and `"external"` disable FastMCP's consent and browser-binding protections. `False` warns about this configuration; `"external"` suppresses the warning because it is an operator acknowledgment that equivalent protections exist elsewhere. Prefer the default `True` unless you own that external authorization flow.
</Warning>
</ParamField>

View file

@ -206,7 +206,7 @@ auth = OIDCProxy(
</ParamField>
<ParamField body="require_authorization_consent" type='bool | Literal["remember", "external"]' default="True">
Consent screen behavior for authorization requests. Accepts `True` (default; always prompt — strongest protection), `"remember"` (silent consent on return visits via signed cookie, gated by `Sec-Fetch-Site` to block AS-in-the-middle attacks), `"external"` (consent handled by upstream IdP or custom page), or `False` (disable entirely; local/testing only). See the [OAuthProxy documentation](/servers/auth/oauth-proxy) for full details on each mode and the security trade-offs.
Consent screen behavior for authorization requests. Accepts `True` (default; always prompt — strongest protection), `"remember"` (silent consent on return visits via signed cookie, gated by `Sec-Fetch-Site` to block AS-in-the-middle attacks), `"external"` (same authorization path as `False`, but the warning is suppressed because the operator asserts that equivalent protections are enforced externally), or `False` (disable entirely; local/testing only). See the [OAuthProxy documentation](/servers/auth/oauth-proxy) for full details on each mode and the security trade-offs.
</ParamField>
<ParamField body="consent_csp_policy" type="str | None" default="None">

View file

@ -296,8 +296,10 @@ auth = OAuthProxy(..., client_storage=MemoryStore())
**`"remember"` — silent consent on return:**
Users see the consent screen on first authorization; subsequent flows from the same browser for the same `(client_id, redirect_uri)` are silently approved via a signed cookie. Cross-site navigations (detected via `Sec-Fetch-Site`) fall back to the prompt. `Sec-Fetch-Site` is a browser-level heuristic rather than a protocol guarantee: an attacker who finds a way to initiate a non-cross-site navigation (XSS on a sibling origin, a same-site redirect chain, etc.) can reach the silent-consent path. `True` does not depend on this signal. See [Confused Deputy Attacks](#confused-deputy-attacks) for the underlying attack class.
**`"external"` — delegate to upstream:**
Skip the built-in consent page; consent is collected by the upstream IdP or a custom login page referenced via `upstream_authorization_endpoint`. No security warning is logged.
**`"external"` — externally managed:**
Follows the same authorization path as `False`: FastMCP skips its consent page and associated browser-binding protections, then redirects directly to the upstream provider. The difference is logging. `False` emits a security warning, while `"external"` suppresses that warning as an explicit acknowledgment that the operator is enforcing equivalent consent and transaction-binding protections elsewhere. FastMCP does not provide or verify those external protections.
Ordinary upstream OAuth consent is generally not equivalent. It typically authorizes FastMCP's shared upstream application without identifying the downstream MCP client or binding approval to that client's transaction. Use `"external"` only when your surrounding authorization system supplies those protections.
**`False` — disable entirely:**
Authorization proceeds directly to the upstream provider without any consent UI. Logs a security warning. Only for local development or testing.
@ -317,7 +319,7 @@ auth = OAuthProxy(..., client_storage=MemoryStore())
```
<Warning>
Disabling consent removes an important security layer. Only disable for local development or testing environments where you fully control all connecting clients.
Both `False` and `"external"` disable FastMCP's consent and browser-binding protections. `False` warns about this configuration; `"external"` suppresses the warning because it is an operator acknowledgment that equivalent protections exist elsewhere. Prefer the default `True` unless you own that external authorization flow.
</Warning>
</ParamField>

View file

@ -199,7 +199,7 @@ auth = OIDCProxy(
</ParamField>
<ParamField body="require_authorization_consent" type='bool | Literal["remember", "external"]' default="True">
Consent screen behavior for authorization requests. Accepts `True` (default; always prompt — strongest protection), `"remember"` (silent consent on return visits via signed cookie, gated by `Sec-Fetch-Site` to block AS-in-the-middle attacks), `"external"` (consent handled by upstream IdP or custom page), or `False` (disable entirely; local/testing only). See the [OAuthProxy documentation](/v2/servers/auth/oauth-proxy) for full details on each mode and the security trade-offs.
Consent screen behavior for authorization requests. Accepts `True` (default; always prompt — strongest protection), `"remember"` (silent consent on return visits via signed cookie, gated by `Sec-Fetch-Site` to block AS-in-the-middle attacks), `"external"` (same authorization path as `False`, but the warning is suppressed because the operator asserts that equivalent protections are enforced externally), or `False` (disable entirely; local/testing only). See the [OAuthProxy documentation](/v2/servers/auth/oauth-proxy) for full details on each mode and the security trade-offs.
</ParamField>
<ParamField body="consent_csp_policy" type="str | None" default="None">

View file

@ -310,8 +310,10 @@ auth = OAuthProxy(..., client_storage=MemoryStore())
**`"remember"` — silent consent on return:**
Users see the consent screen on first authorization; subsequent flows from the same browser for the same `(client_id, redirect_uri)` are silently approved via a signed cookie. Cross-site navigations (detected via `Sec-Fetch-Site`) fall back to the prompt. `Sec-Fetch-Site` is a browser-level heuristic rather than a protocol guarantee: an attacker who finds a way to initiate a non-cross-site navigation (XSS on a sibling origin, a same-site redirect chain, etc.) can reach the silent-consent path. `True` does not depend on this signal. See [Confused Deputy Attacks](#confused-deputy-attacks) for the underlying attack class.
**`"external"` — delegate to upstream:**
Skip the built-in consent page; consent is collected by the upstream IdP or a custom login page referenced via `upstream_authorization_endpoint`. No security warning is logged.
**`"external"` — externally managed:**
Follows the same authorization path as `False`: FastMCP skips its consent page and associated browser-binding protections, then redirects directly to the upstream provider. The difference is logging. `False` emits a security warning, while `"external"` suppresses that warning as an explicit acknowledgment that the operator is enforcing equivalent consent and transaction-binding protections elsewhere. FastMCP does not provide or verify those external protections.
Ordinary upstream OAuth consent is generally not equivalent. It typically authorizes FastMCP's shared upstream application without identifying the downstream MCP client or binding approval to that client's transaction. Use `"external"` only when your surrounding authorization system supplies those protections.
**`False` — disable entirely:**
Authorization proceeds directly to the upstream provider without any consent UI. Logs a security warning. Only for local development or testing.
@ -331,7 +333,7 @@ auth = OAuthProxy(..., client_storage=MemoryStore())
```
<Warning>
Disabling consent removes an important security layer. Only disable for local development or testing environments where you fully control all connecting clients.
Both `False` and `"external"` disable FastMCP's consent and browser-binding protections. `False` warns about this configuration; `"external"` suppresses the warning because it is an operator acknowledgment that equivalent protections exist elsewhere. Prefer the default `True` unless you own that external authorization flow.
</Warning>
</ParamField>

View file

@ -199,7 +199,7 @@ auth = OIDCProxy(
</ParamField>
<ParamField body="require_authorization_consent" type='bool | Literal["remember", "external"]' default="True">
Consent screen behavior for authorization requests. Accepts `True` (default; always prompt — strongest protection), `"remember"` (silent consent on return visits via signed cookie, gated by `Sec-Fetch-Site` to block AS-in-the-middle attacks), `"external"` (consent handled by upstream IdP or custom page), or `False` (disable entirely; local/testing only). See the [OAuthProxy documentation](/servers/auth/oauth-proxy) for full details on each mode and the security trade-offs.
Consent screen behavior for authorization requests. Accepts `True` (default; always prompt — strongest protection), `"remember"` (silent consent on return visits via signed cookie, gated by `Sec-Fetch-Site` to block AS-in-the-middle attacks), `"external"` (same authorization path as `False`, but the warning is suppressed because the operator asserts that equivalent protections are enforced externally), or `False` (disable entirely; local/testing only). See the [OAuthProxy documentation](/servers/auth/oauth-proxy) for full details on each mode and the security trade-offs.
</ParamField>
<ParamField body="consent_csp_policy" type="str | None" default="None">

View file

@ -397,8 +397,10 @@ class OAuthProxy(OAuthProvider, ConsentMixin):
redirect_uri) in the same browser. Cross-site navigations are
still prompted to block AS-in-the-middle attacks. Lower UX
friction, but weaker protection than True.
- "external": skip the built-in consent screen; consent is handled
externally (e.g. by the upstream IdP or a custom login page).
- "external": follow the same authorization path as False, but
suppress the warning as an operator acknowledgment that equivalent
consent and transaction-binding protections are enforced externally.
FastMCP does not provide or verify those external protections.
- False: skip consent entirely. SECURITY WARNING: only set to
False for local development or testing environments.
consent_csp_policy: Content Security Policy for the consent page.

View file

@ -306,8 +306,9 @@ class OIDCProxy(OAuthProxy):
require_authorization_consent: Whether to require user consent before authorizing clients (default True).
When True, users see a consent screen before being redirected to the upstream IdP.
When False, authorization proceeds directly without user confirmation.
When "external", the built-in consent screen is skipped but no warning is
logged, indicating that consent is handled externally (e.g. by the upstream IdP).
When "external", authorization follows the same direct path as False,
but the warning is suppressed as an operator acknowledgment that
equivalent protections are enforced externally.
SECURITY WARNING: Only set to False for local development or testing environments.
consent_csp_policy: Content Security Policy for the consent page.
If None (default), uses the built-in CSP policy with appropriate directives.

View file

@ -135,8 +135,9 @@ class Auth0Provider(OIDCProxy):
require_authorization_consent: Whether to require user consent before authorizing clients (default True).
When True, users see a consent screen before being redirected to Auth0.
When False, authorization proceeds directly without user confirmation.
When "external", the built-in consent screen is skipped but no warning is
logged, indicating that consent is handled externally (e.g. by the upstream IdP).
When "external", authorization follows the same direct path as False,
but the warning is suppressed as an operator acknowledgment that
equivalent protections are enforced externally.
SECURITY WARNING: Only set to False for local development or testing environments.
fallback_refresh_token_expiry_seconds: Lifetime for the FastMCP-issued
refresh token when the upstream provider omits `refresh_expires_in`

View file

@ -175,8 +175,9 @@ class AWSCognitoProvider(OIDCProxy):
require_authorization_consent: Whether to require user consent before authorizing clients (default True).
When True, users see a consent screen before being redirected to AWS Cognito.
When False, authorization proceeds directly without user confirmation.
When "external", the built-in consent screen is skipped but no warning is
logged, indicating that consent is handled externally (e.g. by the upstream IdP).
When "external", authorization follows the same direct path as False,
but the warning is suppressed as an operator acknowledgment that
equivalent protections are enforced externally.
SECURITY WARNING: Only set to False for local development or testing environments.
fallback_refresh_token_expiry_seconds: Lifetime for the FastMCP-issued
refresh token when the upstream provider omits `refresh_expires_in`

View file

@ -173,8 +173,9 @@ class AzureProvider(OAuthProxy):
require_authorization_consent: Whether to require user consent before authorizing clients (default True).
When True, users see a consent screen before being redirected to Azure.
When False, authorization proceeds directly without user confirmation.
When "external", the built-in consent screen is skipped but no warning is
logged, indicating that consent is handled externally (e.g. by the upstream IdP).
When "external", authorization follows the same direct path as False,
but the warning is suppressed as an operator acknowledgment that
equivalent protections are enforced externally.
SECURITY WARNING: Only set to False for local development or testing environments.
http_client: Optional httpx2.AsyncClient for connection pooling in JWKS fetches.
When provided, the client is reused for JWT key fetches and the caller

View file

@ -327,8 +327,9 @@ class ClerkProvider(OAuthProxy):
into a 32-byte key. If not provided, the upstream client secret will be used to
derive a 32-byte key using PBKDF2.
require_authorization_consent: Whether to require user consent before authorizing
clients (default True). When "external", the built-in consent screen is skipped
but no warning is logged, indicating that consent is handled externally by Clerk.
clients (default True). When "external", authorization follows the same direct
path as False, but the warning is suppressed as an operator acknowledgment that
equivalent protections are enforced externally.
consent_csp_policy: Custom CSP policy for the consent page.
extra_authorize_params: Additional parameters to forward to Clerk's authorization
endpoint. Example: {"prompt": "login"} to force re-authentication.

View file

@ -241,8 +241,9 @@ class DiscordProvider(OAuthProxy):
require_authorization_consent: Whether to require user consent before authorizing clients (default True).
When True, users see a consent screen before being redirected to Discord.
When False, authorization proceeds directly without user confirmation.
When "external", the built-in consent screen is skipped but no warning is
logged, indicating that consent is handled externally (e.g. by the upstream IdP).
When "external", authorization follows the same direct path as False,
but the warning is suppressed as an operator acknowledgment that
equivalent protections are enforced externally.
SECURITY WARNING: Only set to False for local development or testing environments.
http_client: Optional httpx2.AsyncClient for connection pooling in token verification.
When provided, the client is reused across verify_token calls and the caller

View file

@ -257,8 +257,9 @@ class GitHubProvider(OAuthProxy):
require_authorization_consent: Whether to require user consent before authorizing clients (default True).
When True, users see a consent screen before being redirected to GitHub.
When False, authorization proceeds directly without user confirmation.
When "external", the built-in consent screen is skipped but no warning is
logged, indicating that consent is handled externally (e.g. by the upstream IdP).
When "external", authorization follows the same direct path as False,
but the warning is suppressed as an operator acknowledgment that
equivalent protections are enforced externally.
SECURITY WARNING: Only set to False for local development or testing environments.
http_client: Optional httpx2.AsyncClient for connection pooling in token verification.
When provided, the client is reused across verify_token calls and the caller

View file

@ -290,8 +290,9 @@ class GoogleProvider(OAuthProxy):
require_authorization_consent: Whether to require user consent before authorizing clients (default True).
When True, users see a consent screen before being redirected to Google.
When False, authorization proceeds directly without user confirmation.
When "external", the built-in consent screen is skipped but no warning is
logged, indicating that consent is handled externally (e.g. by Google's own consent).
When "external", authorization follows the same direct path as False,
but the warning is suppressed as an operator acknowledgment that
equivalent protections are enforced externally.
SECURITY WARNING: Only set to False for local development or testing environments.
extra_authorize_params: Additional parameters to forward to Google's authorization endpoint.
By default, GoogleProvider sets {"access_type": "offline", "prompt": "consent"} to ensure

View file

@ -213,8 +213,9 @@ class WorkOSProvider(OAuthProxy):
require_authorization_consent: Whether to require user consent before authorizing clients (default True).
When True, users see a consent screen before being redirected to WorkOS.
When False, authorization proceeds directly without user confirmation.
When "external", the built-in consent screen is skipped but no warning is
logged, indicating that consent is handled externally (e.g. by the upstream IdP).
When "external", authorization follows the same direct path as False,
but the warning is suppressed as an operator acknowledgment that
equivalent protections are enforced externally.
SECURITY WARNING: Only set to False for local development or testing environments.
extra_authorize_params: Additional parameters to forward to WorkOS's authorization endpoint.
Useful for forcing scopes like `offline_access` so WorkOS issues a refresh token,