fix: make oauth login flow interactive
This commit is contained in:
@@ -149,16 +149,28 @@ async def _login_with_pasted_response(
|
||||
provider,
|
||||
client_id: str,
|
||||
client_secret: str | None,
|
||||
authorization_response: str,
|
||||
authorization_response: str | None,
|
||||
) -> OAuthLoginResult:
|
||||
from authlib.integrations.httpx_client import AsyncOAuth2Client
|
||||
|
||||
def prompt_for_authorization_response(
|
||||
authorization_url: str,
|
||||
state: str,
|
||||
) -> str | None:
|
||||
if authorization_response is not None:
|
||||
return None
|
||||
typer.echo("Open this URL in your browser to authorize access:")
|
||||
typer.echo(authorization_url)
|
||||
typer.echo(f"Expected OAuth state: {state}")
|
||||
return typer.prompt("Paste the full redirected callback URL")
|
||||
|
||||
flow = OAuthCodeLoginFlow(client_factory=AsyncOAuth2Client) # type: ignore[arg-type]
|
||||
return await flow.login_with_authorization_response(
|
||||
provider=provider,
|
||||
client_id=client_id,
|
||||
client_secret=client_secret,
|
||||
authorization_response=authorization_response,
|
||||
authorization_url_callback=prompt_for_authorization_response,
|
||||
)
|
||||
|
||||
|
||||
@@ -168,12 +180,15 @@ def oauth_login(
|
||||
provider_name: Annotated[str, typer.Argument(help="Auth provider profile name.")],
|
||||
auth_ref: Annotated[str, typer.Option("--id", help="Auth record id/ref to save.")],
|
||||
authorization_response: Annotated[
|
||||
str,
|
||||
str | None,
|
||||
typer.Option(
|
||||
"--authorization-response",
|
||||
help="Full redirected callback URL after login.",
|
||||
help=(
|
||||
"Full redirected callback URL after login. If omitted, prints "
|
||||
"the authorization URL and prompts for the callback URL."
|
||||
),
|
||||
),
|
||||
],
|
||||
] = None,
|
||||
) -> None:
|
||||
"""Run an OAuth login flow and save the resulting refresh token as an auth record."""
|
||||
from wf_config import load_workflow_config
|
||||
|
||||
+13
-2
@@ -67,15 +67,26 @@ class OAuthCodeLoginFlow:
|
||||
provider: OAuthProviderConfig,
|
||||
client_id: str,
|
||||
client_secret: str | None,
|
||||
authorization_response: str,
|
||||
authorization_response: str | None,
|
||||
authorization_url_callback: Callable[[str, str], str | None] | None = None,
|
||||
) -> OAuthLoginResult:
|
||||
client = self._client_factory(
|
||||
client_id=client_id,
|
||||
client_secret=client_secret,
|
||||
scope=" ".join(provider.scopes),
|
||||
redirect_uri=provider.redirect_uri,
|
||||
code_challenge_method="S256",
|
||||
)
|
||||
client.create_authorization_url(str(provider.auth_url))
|
||||
authorization_url, state = client.create_authorization_url(
|
||||
str(provider.auth_url),
|
||||
redirect_uri=provider.redirect_uri,
|
||||
)
|
||||
if authorization_url_callback is not None:
|
||||
callback_response = authorization_url_callback(authorization_url, state)
|
||||
if authorization_response is None:
|
||||
authorization_response = callback_response
|
||||
if authorization_response is None:
|
||||
raise ValueError("OAuth authorization response is required")
|
||||
token = await client.fetch_token(
|
||||
str(provider.token_url),
|
||||
authorization_response=authorization_response,
|
||||
|
||||
Reference in New Issue
Block a user