mirror of
https://github.com/PrefectHQ/fastmcp.git
synced 2026-08-23 22:14:18 +02:00
Add valid_scopes and extra_authorize_params to WorkOSProvider (#4135)
This commit is contained in:
parent
7cfcaf22b8
commit
b0fb2c3ae6
2 changed files with 89 additions and 0 deletions
|
|
@ -168,6 +168,7 @@ class WorkOSProvider(OAuthProxy):
|
|||
issuer_url: AnyHttpUrl | str | None = None,
|
||||
redirect_path: str | None = None,
|
||||
required_scopes: list[str] | None = None,
|
||||
valid_scopes: list[str] | None = None,
|
||||
timeout_seconds: int = 10,
|
||||
allowed_client_redirect_uris: list[str] | None = None,
|
||||
client_storage: AsyncKeyValue | None = None,
|
||||
|
|
@ -176,6 +177,7 @@ class WorkOSProvider(OAuthProxy):
|
|||
consent_csp_policy: str | None = None,
|
||||
forward_resource: bool = True,
|
||||
fallback_refresh_token_expiry_seconds: int | None = None,
|
||||
extra_authorize_params: dict[str, str] | None = None,
|
||||
http_client: httpx.AsyncClient | None = None,
|
||||
enable_cimd: bool = True,
|
||||
):
|
||||
|
|
@ -192,6 +194,10 @@ class WorkOSProvider(OAuthProxy):
|
|||
to avoid 404s during discovery when mounting under a path.
|
||||
redirect_path: Redirect path configured in WorkOS (defaults to "/auth/callback")
|
||||
required_scopes: Required OAuth scopes (no default)
|
||||
valid_scopes: All scopes that clients are allowed to request, advertised through
|
||||
well-known endpoints. Defaults to required_scopes if not provided. Use this
|
||||
when you want clients to be able to request additional scopes beyond the
|
||||
required minimum.
|
||||
timeout_seconds: HTTP request timeout for WorkOS API calls (defaults to 10)
|
||||
allowed_client_redirect_uris: List of allowed redirect URI patterns for MCP clients.
|
||||
If None (default), all URIs are allowed. If empty list, no URIs are allowed.
|
||||
|
|
@ -207,6 +213,9 @@ class WorkOSProvider(OAuthProxy):
|
|||
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).
|
||||
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,
|
||||
e.g. ``{"scope": "openid profile email offline_access"}``.
|
||||
http_client: Optional httpx.AsyncClient for connection pooling in token verification.
|
||||
When provided, the client is reused across verify_token calls and the caller
|
||||
is responsible for its lifecycle. When None (default), a fresh client is created per call.
|
||||
|
|
@ -221,6 +230,9 @@ class WorkOSProvider(OAuthProxy):
|
|||
scopes_final = (
|
||||
parse_scopes(required_scopes) if required_scopes is not None else []
|
||||
)
|
||||
valid_scopes_final = (
|
||||
parse_scopes(valid_scopes) if valid_scopes is not None else None
|
||||
)
|
||||
|
||||
# Create WorkOS token verifier
|
||||
token_verifier = WorkOSTokenVerifier(
|
||||
|
|
@ -248,6 +260,8 @@ class WorkOSProvider(OAuthProxy):
|
|||
consent_csp_policy=consent_csp_policy,
|
||||
forward_resource=forward_resource,
|
||||
fallback_refresh_token_expiry_seconds=fallback_refresh_token_expiry_seconds,
|
||||
extra_authorize_params=extra_authorize_params,
|
||||
valid_scopes=valid_scopes_final,
|
||||
enable_cimd=enable_cimd,
|
||||
)
|
||||
|
||||
|
|
|
|||
|
|
@ -103,6 +103,81 @@ class TestWorkOSProvider:
|
|||
assert provider._redirect_path == "/auth/callback"
|
||||
# WorkOS provider has no default scopes but we can't easily verify without accessing internals
|
||||
|
||||
def test_extra_authorize_params_default_none(self, memory_storage: MemoryStore):
|
||||
"""WorkOS doesn't set provider-specific defaults — empty unless caller opts in."""
|
||||
provider = WorkOSProvider(
|
||||
client_id="test_client",
|
||||
client_secret="test_secret",
|
||||
authkit_domain="https://test.authkit.app",
|
||||
base_url="https://myserver.com",
|
||||
jwt_signing_key="test-secret",
|
||||
client_storage=memory_storage,
|
||||
)
|
||||
|
||||
assert provider._extra_authorize_params == {}
|
||||
|
||||
def test_extra_authorize_params_passed_through(self, memory_storage: MemoryStore):
|
||||
"""Caller-supplied params are forwarded to the upstream authorize URL.
|
||||
|
||||
Common use case: force `offline_access` into the scope so WorkOS issues
|
||||
a refresh token.
|
||||
"""
|
||||
provider = WorkOSProvider(
|
||||
client_id="test_client",
|
||||
client_secret="test_secret",
|
||||
authkit_domain="https://test.authkit.app",
|
||||
base_url="https://myserver.com",
|
||||
jwt_signing_key="test-secret",
|
||||
client_storage=memory_storage,
|
||||
extra_authorize_params={
|
||||
"scope": "openid profile email offline_access",
|
||||
},
|
||||
)
|
||||
|
||||
assert provider._extra_authorize_params == {
|
||||
"scope": "openid profile email offline_access",
|
||||
}
|
||||
|
||||
def test_valid_scopes_passed_through(self, memory_storage: MemoryStore):
|
||||
"""valid_scopes is forwarded to OAuthProxy and advertised via DCR."""
|
||||
provider = WorkOSProvider(
|
||||
client_id="test_client",
|
||||
client_secret="test_secret",
|
||||
authkit_domain="https://test.authkit.app",
|
||||
base_url="https://myserver.com",
|
||||
required_scopes=["openid"],
|
||||
valid_scopes=["openid", "profile", "email", "offline_access"],
|
||||
jwt_signing_key="test-secret",
|
||||
client_storage=memory_storage,
|
||||
)
|
||||
|
||||
reg_options = provider.client_registration_options
|
||||
assert reg_options is not None
|
||||
assert reg_options.valid_scopes is not None
|
||||
assert set(reg_options.valid_scopes) == {
|
||||
"openid",
|
||||
"profile",
|
||||
"email",
|
||||
"offline_access",
|
||||
}
|
||||
|
||||
def test_valid_scopes_defaults_to_required(self, memory_storage: MemoryStore):
|
||||
"""When valid_scopes is omitted, the OAuthProxy falls back to required_scopes."""
|
||||
provider = WorkOSProvider(
|
||||
client_id="test_client",
|
||||
client_secret="test_secret",
|
||||
authkit_domain="https://test.authkit.app",
|
||||
base_url="https://myserver.com",
|
||||
required_scopes=["openid", "profile"],
|
||||
jwt_signing_key="test-secret",
|
||||
client_storage=memory_storage,
|
||||
)
|
||||
|
||||
reg_options = provider.client_registration_options
|
||||
assert reg_options is not None
|
||||
assert reg_options.valid_scopes is not None
|
||||
assert set(reg_options.valid_scopes) == {"openid", "profile"}
|
||||
|
||||
def test_oauth_endpoints_configured_correctly(self, memory_storage: MemoryStore):
|
||||
"""Test that OAuth endpoints are configured correctly."""
|
||||
provider = WorkOSProvider(
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue