Non-interactive login: a supported way to obtain the authorization URL programmatically
Problem Statement
claude auth login is an interactive TUI. There is no --json, no --print-url, and no
machine-readable output, which makes it very hard to authenticate Claude Code in an
environment that has no terminal — a container, a pod, a CI-adjacent runner, or a
web UI that provisions dev workspaces.
I run claude remote-control in Kubernetes pods so I can pick work back up from my phone
on any of my projects. Everything else in that setup is fully declarative: repositories,
git identity, deploy keys, commit signing. Authentication is the single step that still
requires a human to open an interactive shell into the pod:
kubectl exec -it deploy/my-workspace -- claude auth login
I want to be clear about what I am not asking for: I am not looking for a way to skip
the human. OAuth requires the account owner to approve in a browser, and that is correct.claude setup-token / CLAUDE_CODE_OAUTH_TOKEN are inference-only and rightly rejected
by Remote Control. One workspace belongs to one person, with their own subscription and
their own credentials — nothing is pooled.
What I want is to move the approval step out of the terminal and into an interface,
so the user clicks a button, approves in their browser, and pastes the code back.
Proposed Solution
A supported, non-interactive entry point to the login flow. Something like:
claude auth login --claudeai --print-url --json
returning, on stdout:
{"authorization_url": "https://claude.com/cai/oauth/authorize?...", "state": "..."}
and a matching way to submit the authorization code:
claude auth login --code "<code>"
Exit codes and a stable JSON shape would be enough. Nothing about the security model
changes: same PKCE flow, same manual redirect to platform.claude.com/oauth/code/callback,
same human approving in their own browser.
Alternative Solutions
What I do today, and why it is unsatisfying. I allocate a pseudo-terminal to the CLI
with script, scrape the authorization URL out of its output, and feed the code back
through a FIFO held open so the CLI does not see EOF. It works, and it is in production
for my own workspaces.
But it is screen-scraping a TUI, so it is not a contract. Two failures I hit while
building it, neither of which is discoverable from documentation:
- once ANSI escapes are stripped, the two copies of the OSC 8 hyperlink end up
concatenated with no separator, so a greedy pattern captures the URL twice;
- truncating the URL on a naive character class cuts it at the first
/of the path.
Any cosmetic change to the TUI breaks this silently, and the only symptom is "no
authorization URL found". I pin the CLI version in my image because of it, and I keep the
manual command documented as a fallback. That is a lot of scaffolding to work around the
absence of one flag.
I am aware there may be internal mechanisms intended for exactly this. I have
deliberately not built on anything undocumented, and I would rather have a supported
path — happy to discuss specifics privately if that is useful.
Priority
Important - Significantly improves my workflow
Feature Category
Authentication / Remote Control
This issue has 1 comment on GitHub. Read the full discussion on GitHub ↗