How to Handle OAuth for OpenClaw Workflows on a Headless Server
How to Authorize Terminal and Server-Based Tools on a Headless Machine Without a Browser
If you work on remote servers long enough, you eventually run into the same annoying problem: a terminal-based or server-side tool wants OAuth, but your server has no browser.
This sounds like a small inconvenience until it blocks real work. You run a command, start a tool, or launch an MCP-related flow, and suddenly the whole setup breaks down because the machine where the auth flow begins and the machine where you can actually log in are not the same machine.
This is a very common pattern in practice:
- the tool runs on a VPS or headless server,
- your browser is on your laptop,
- and the software assumes both are on the same device.
That assumption is often wrong.
I ran into this enough times that I ended up turning the solution into an OpenClaw skill: headless-oauth. It teaches the agent how to guide OAuth flows on a headless machine without pretending the server has a browser.
The interesting part is not the skill itself. The interesting part is the pattern.
Why this problem matters more now
I think this problem became much more relevant with the spread of OpenClaw and similar agent setups.
Once you start using more server-based tools, MCP servers, and terminal-centric workflows, OAuth friction shows up everywhere. A lot of useful tools require this kind of authorization, and the moment your setup stops living on a laptop and starts living on a server, the whole thing becomes more awkward.
That is part of the reason I generally prefer serious OpenClaw setups on a server rather than on a personal laptop. I wrote more about that here: The Best Way to Host OpenClaw: What I Learned from Trying 3 Setups.
The point is that once you move into a more professional server-based setup — which I think is usually the right direction — you immediately run into the missing-browser problem much more often.
The real problem
A lot of modern tools rely on OAuth:
- GitHub CLI
- Google Cloud CLI
- Google-related terminal tools like
gog - MCP tools and MCP servers
- ClickUp MCP
- custom internal tools
- anything terminal-based or server-based that assumes a user can complete login in a normal browser
The friction starts when that tool is running on a remote machine.
In theory, the auth flow is simple:
- the tool generates a URL or a code,
- the user completes login in a browser,
- the tool receives a token,
- the session is stored on the server.
In practice, there are several ways this breaks:
- the tool tries to open a browser that does not exist,
- it starts a localhost callback server that your laptop cannot reach,
- it stores credentials in a keyring that is not available in a headless session,
- or it just fails with an unhelpful error message.
The underlying issue is simple: OAuth flows often assume local continuity between the tool and the browser. On a VPS or headless machine, that continuity is gone.
The correct mental model
The mistake is to think: “how do I make the server behave like it has a browser?”
The better question is: how do I split the OAuth flow across two machines cleanly?
Once you think about it that way, the problem becomes much more manageable.
The server does not need a browser. It needs a way to:
- generate the right auth state,
- hand the user the right URL or code,
- receive the necessary callback information back,
- and complete the token exchange safely.
So the real model looks more like this:
Server
- starts auth flow
- generates URL / code / callback expectation
- waits for auth result
Local machine
- opens the URL
- completes login
- returns the required redirect URL or code
That is the whole trick.
Three patterns that keep showing up
After doing this a few times, I found that most headless OAuth problems fall into one of three patterns.
1. URL generated on the server, completed on the local machine
This is the cleanest pattern.
The tool prints an authorization URL. You open it on your own machine, log in, and then paste the resulting redirect URL or code back.
This works well when the tool is already designed to separate “start auth” and “finish auth”.
Typical examples:
gcloudgog- some Google-related tools
- various OAuth-capable internal tools
The important thing is that the agent should clearly explain the split:
- “I will generate the URL on the server”
- “You open it locally”
- “Then paste back the redirect URL or the returned code”
That removes most of the confusion.
2. Device flow
This is the best case.
Instead of a browser redirect, the tool gives you:
- a short code
- and a URL like
github.com/login/device
You open the URL on your laptop, enter the code, and the server-side process keeps polling until authentication completes.
This is exactly the kind of flow that behaves well on a headless machine.
A good example is GitHub CLI:
gh auth login --hostname github.com --git-protocol https --no-launch-browser
It gives the user a one-time code, and the server-side process waits for the confirmation.
This is much more robust than browser callback flows.
3. Manual callback relay
This is the ugly one, but it matters because it appears in real life.
Some tools start a local callback server and expect the browser to redirect back into something like:
http://localhost:XXXX/callback?...
That obviously breaks when the browser is on your laptop and the server-side process is on a VPS.
In those cases, the workaround is often:
- let the user complete the flow in the browser,
- copy the final failed redirect URL,
- and relay that URL back manually so the headless tool can finish processing it.
It is not elegant, but it works surprisingly often.
This pattern shows up with some MCP-related tools and custom auth flows. ClickUp MCP is a good example because it makes it obvious that this is not really about CLIs specifically — it is about terminal and server-based software that begins OAuth on one machine and needs a human to finish it somewhere else.
Why agents are useful here
A human can do all of this manually, but it is annoying because the process is procedural and easy to mess up.
The agent helps in two ways:
- it recognizes which auth pattern is happening,
- it gives the user the exact next step instead of vague instructions.
That is what I wanted from headless-oauth.
Not “do OAuth magically”, but:
- identify the flow,
- explain the remote/local split correctly,
- avoid false assumptions,
- and guide the user to a successful token exchange.
That is much more realistic.
What usually goes wrong
There are a few recurring failure modes.
The tool tries to open a browser
This is the simplest one. The fix is usually to force a no-browser mode:
--no-launch-browser- device flow mode
- printed URL mode
The redirect URI is wrong
A lot of people accidentally use a Web app OAuth client where a Desktop app client is required.
That often causes:
redirect_uri_mismatch- blocked flows
- impossible callback behavior on headless machines
The tool stores credentials in an unavailable keyring
Even if the OAuth flow succeeds, token persistence can fail if the tool expects an interactive desktop keyring.
That is not really an OAuth problem — it is a credential storage problem — but it looks like auth failure from the outside.
The agent explains the wrong machine boundary
This is more subtle, but important.
If the agent talks as if the browser and the tool are on the same device, the user gets confused immediately. The instructions must explicitly respect the fact that:
- the server is remote,
- the browser is local,
- and the auth flow crosses that boundary.
Why this was worth turning into a skill
I like tools that solve very specific pain.
This is one of those cases where the problem is narrow, but very real:
- not a vague “AI productivity” thing,
- not another wrapper around an API,
- just a concrete operational problem that comes up whenever you manage real systems.
I turned it into a skill because this kind of knowledge is procedural. Once you understand the flow patterns, they can be reused across many different tools.
That is exactly the kind of thing I want agents to know: not abstract advice, but operational patterns that save time and reduce failure.
The broader lesson
A lot of infrastructure problems are really boundary problems.
The system fails not because OAuth is fundamentally broken, but because the tool assumes one environment and the user is actually operating across two:
- remote server
- local browser
Once you model the system correctly, the fix becomes much simpler.
That is a pattern I keep seeing in agent work in general. The hard part is often not writing code or calling an API. It is noticing where the assumptions break, and redesigning the workflow around the real environment instead of the imagined one.
Headless OAuth is a small example of that, but a very practical one.
The skill
I published the skill here:
- ClawHub:
headless-oauth - GitHub:
IgorIvanter/headless-oauth
It supports the three patterns above and is meant for terminal-based and server-based software that needs OAuth on a headless machine where the user and the browser are on a different device.