fix: forward redirect_path through KeycloakOAuthProxy for custom callbacks

🤖 Generated with Claude Code

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
This commit is contained in:
strawgate 2026-05-17 12:11:59 -05:00
commit f19df2dce7
2 changed files with 34 additions and 0 deletions

View file

@ -132,6 +132,7 @@ class KeycloakOAuthProxy(OAuthProxy):
upstream_authorization_endpoint: str | None = None,
upstream_token_endpoint: str | None = None,
upstream_revocation_endpoint: str | None = None,
redirect_path: str | None = None,
# Pass-through OAuthProxy options
jwt_signing_key: str | bytes | None = None,
client_storage: AsyncKeyValue | None = None,
@ -162,6 +163,11 @@ class KeycloakOAuthProxy(OAuthProxy):
upstream_token_endpoint: Override the token endpoint URL.
Required if `realm_url` is not provided.
upstream_revocation_endpoint: Optional token revocation endpoint.
redirect_path: Callback path registered with the upstream Keycloak
client. Defaults to `/auth/callback`. Set this when migrating an
existing deployment whose Keycloak client uses a non-default
callback path, so the authorization request keeps matching the
registered redirect URI.
jwt_signing_key: Secret for signing FastMCP JWTs.
client_storage: Storage backend for OAuth state.
require_authorization_consent: Consent screen behaviour (default True).
@ -216,6 +222,7 @@ class KeycloakOAuthProxy(OAuthProxy):
upstream_client_secret=upstream_client_secret,
token_verifier=token_verifier,
valid_scopes=parsed_valid_scopes,
redirect_path=redirect_path,
base_url=base_url,
jwt_signing_key=jwt_signing_key,
client_storage=client_storage,

View file

@ -968,6 +968,33 @@ class TestKeycloakOAuthProxy:
"offline_access",
]
def test_redirect_path_defaults_to_auth_callback(self, jwt_verifier):
proxy = KeycloakOAuthProxy(
realm_url="https://keycloak.example.com/realms/test",
upstream_client_id="test-client",
upstream_client_secret="test-secret",
token_verifier=jwt_verifier,
base_url="https://proxy.example.com",
jwt_signing_key="test-secret-key",
client_storage=MemoryStore(),
)
assert proxy._redirect_path == "/auth/callback"
def test_redirect_path_forwarded_for_custom_callback(self, jwt_verifier):
"""Migrating a deployment whose Keycloak client uses a non-default
callback path must not silently revert to /auth/callback."""
proxy = KeycloakOAuthProxy(
realm_url="https://keycloak.example.com/realms/test",
upstream_client_id="test-client",
upstream_client_secret="test-secret",
token_verifier=jwt_verifier,
base_url="https://proxy.example.com",
redirect_path="/custom/oauth/callback",
jwt_signing_key="test-secret-key",
client_storage=MemoryStore(),
)
assert proxy._redirect_path == "/custom/oauth/callback"
async def test_refresh_expires_in_zero_subsequent_refresh_does_not_shrink(
self, proxy
):