Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
46 changes: 37 additions & 9 deletions crates/aspect-cli/src/builtins/aspect/auth.axl
Original file line number Diff line number Diff line change
Expand Up @@ -3,17 +3,31 @@ load("./private/lib/deployment_flags.axl", "REMOTE_DEFAULT_CAPS", "capability_la
load("./private/lib/environment.axl", "error", "info", "warn")
load("./private/lib/prompt.axl", "prompt_choice")

def _run_browser_login(ctx: TaskContext, deployment: str):
"""Open the deployment's authorize URL in a browser and wait for the callback,
returning the minted credentials. Prints the URL if a browser can't be opened."""
def _run_browser_login(ctx: TaskContext, deployment: str) -> aspect.auth.AuthCredentials | None:
session = ctx.aspect.auth.login(deployment = deployment)
result = ctx.std.process.command("open").arg(session.url).spawn().wait()
if not result.success:
print("Open this URL to log in:")
print(" " + session.url)
else:
opened = not ctx.args.no_browser and session.open_browser()
if opened:
print("Browser opened. Waiting for authentication...")
return session.wait()
print("(Nothing opened, or it opened elsewhere? Ctrl-C and re-run with --no-browser.)")
return session.finish()

print("Open this URL in a browser to log in:")
print("")
print(" " + session.url)
print("")
if not ctx.args.no_browser and not ctx.std.io.stdin.is_tty:
print("Waiting for the callback on localhost...")
return session.finish()

print("If the browser is on another machine, its localhost callback will fail.")
print("Copy the callback URL from the address bar and paste it below.")
print("")
ctx.std.io.stdout.write("Paste the callback URL (or just the code): ")
ctx.std.io.stdout.flush()
pasted = str(ctx.std.io.stdin.read(8192)).strip()
if not pasted:
return None
return session.finish(pasted)

# Width of the label column in a deployment's detail block so values align. Must
# be wider than the longest label ("Results", 7) to leave a gap; a label >= this
Expand Down Expand Up @@ -124,6 +138,9 @@ def _login_impl(ctx: TaskContext) -> int:
creds = ctx.aspect.auth.login(api_token = inp, deployment = deployment)
else:
creds = _run_browser_login(ctx, deployment)
if creds == None:
error(ctx.std, "No authorization code entered; not logged in.")
return 1

# Persist under the deployment's own profile (so endpoint auth resolves it by
# host) unless the user pinned an explicit --profile.
Expand All @@ -149,6 +166,10 @@ login = task(
"deployment": args.string(
description = "Log in to this configured Workflows deployment (see `aspect auth configure`) instead of your Aspect account. Selects which account/deployment to authenticate.",
),
"no_browser": args.boolean(
default = False,
description = "Don't open a browser locally; print the URL and ask for the callback URL or authorization code. Use this when the browser is on another machine, such as over SSH.",
),
"profile": args.string(
description = "Advanced: the credential store key to save under (defaults to the deployment name, or \"default\" for the Aspect account). Unlike --deployment (which picks who to authenticate), --profile only changes where the credential is filed — use it to keep two identities for the same account/deployment side by side. Also settable via $ASPECT_AUTH_PROFILE.",
),
Expand Down Expand Up @@ -222,6 +243,9 @@ def _configure_impl(ctx: TaskContext) -> int:
print("(interactively, or with an API token via --with-api-token).")
return 0
creds = _run_browser_login(ctx, info.name)
if creds == None:
error(ctx.std, "No authorization code entered; the deployment is configured but not logged in.")
return 1
ctx.aspect.auth.persist(creds, profile = info.name)
print("")
summary = ctx.aspect.auth.deployment_summary(info.name)
Expand Down Expand Up @@ -253,6 +277,10 @@ configure = task(
default = True,
description = "Run the interactive login after configuring.",
),
"no_browser": args.boolean(
default = False,
description = "Don't open a browser locally; print the URL and ask for the callback URL or authorization code. Use this when the browser is on another machine, such as over SSH.",
),
},
)

Expand Down
Loading
Loading