From 0ede8c63b5fa55106605a5b4b716f0dbcd5aec15 Mon Sep 17 00:00:00 2001 From: Yash Goel <162511050+yashhzd@users.noreply.github.com> Date: Fri, 13 Feb 2026 13:00:19 +0000 Subject: [PATCH] feat: allow setting redirect URI port for OAuth flow Adds a `redirect_port` parameter to `Issuer.identity_token()` that allows callers to specify a fixed port for the local OAuth redirect server. This is needed for enterprise OIDC providers that require pre-registered redirect URIs and don't allow wildcard localhost ports. The default remains `0` (ephemeral port), preserving backward compatibility. Fixes #1029 Signed-off-by: Yash Goel Signed-off-by: Yash Goel --- sigstore/_internal/oidc/oauth.py | 26 +++++++++++++++++++------- sigstore/oidc.py | 10 +++++++++- 2 files changed, 28 insertions(+), 8 deletions(-) diff --git a/sigstore/_internal/oidc/oauth.py b/sigstore/_internal/oidc/oauth.py index 632c7482..df9d0b05 100644 --- a/sigstore/_internal/oidc/oauth.py +++ b/sigstore/_internal/oidc/oauth.py @@ -87,9 +87,9 @@ @@ -102,12 +102,18 @@ class _OAuthFlow: - def __init__(self, client_id: str, client_secret: str, issuer: Issuer): + def __init__( + self, + client_id: str, + client_secret: str, + issuer: Issuer, + redirect_port: int = 0, + ): self._client_id = client_id self._client_secret = client_secret self._issuer = issuer self._server = _OAuthRedirectServer( - self._client_id, self._client_secret, self._issuer + self._client_id, self._client_secret, self._issuer, port=redirect_port ) self._server_thread = threading.Thread( target=lambda server: server.serve_forever(), @@ -223,8 +229,14 @@ def _auth_params(self, redirect_uri: str) -> dict[str, Any]: class _OAuthRedirectServer(http.server.HTTPServer): - def __init__(self, client_id: str, client_secret: str, issuer: Issuer) -> None: - super().__init__(("localhost", 0), _OAuthRedirectHandler) + def __init__( + self, + client_id: str, + client_secret: str, + issuer: Issuer, + port: int = 0, + ) -> None: + super().__init__(("localhost", port), _OAuthRedirectHandler) self.oauth_session = _OAuthSession(client_id, client_secret, issuer) self.auth_response: dict[str, list[str]] | None = None self._is_out_of_band = False diff --git a/sigstore/oidc.py b/sigstore/oidc.py index bc5cd875..7ed57bfc 100644 --- a/sigstore/oidc.py +++ b/sigstore/oidc.py @@ -274,6 +274,7 @@ def identity_token( # nosec: B107 client_id: str = _DEFAULT_CLIENT_ID, client_secret: str = "", force_oob: bool = False, + redirect_port: int = 0, ) -> IdentityToken: """ Retrieves and returns an `IdentityToken` from the current `Issuer`, via OAuth. @@ -283,6 +284,11 @@ def identity_token( # nosec: B107 The `force_oob` flag controls the kind of flow performed. When `False` (the default), this function attempts to open the user's web browser before falling back to an out-of-band flow. When `True`, the out-of-band flow is always used. + + The `redirect_port` parameter controls the port used for the local redirect server + during the OAuth flow. When `0` (the default), an ephemeral port is chosen by the OS. + Set this to a specific port number when your OIDC provider requires a pre-registered + redirect URI with a fixed port. """ # This function and the components that it relies on are based off of: @@ -291,7 +297,9 @@ def identity_token( # nosec: B107 from sigstore._internal.oidc.oauth import _OAuthFlow code: str - with _OAuthFlow(client_id, client_secret, self) as server: + with _OAuthFlow( + client_id, client_secret, self, redirect_port=redirect_port + ) as server: # Launch web browser if not force_oob and webbrowser.open(server.base_uri): print("Waiting for browser interaction...", file=sys.stderr)