docs(github-auth): document headless gh auth login --with-token hang + hosts.yml fallback

On keyring-less headless Linux (VPS, containers, no dbus session),
'gh auth login --with-token' can block indefinitely waiting on a
secret-service keyring -- even with --insecure-storage, with no output.
Hit live on a headless x86_64 VPS (gh 2.97.0): the documented device
flow succeeded up to the token, then --with-token hung twice.

- Add a timeout guard to the device-flow polling loop so the hang is
  detected instead of silently stalling the login.
- Document the proven fallback: write ~/.config/gh/hosts.yml directly
  (chmod 600) and run 'gh auth setup-git' -- both read the file store
  without touching the keyring.
This commit is contained in:
Teknium
2026-08-12 14:05:53 -07:00
parent d2c6af3aa2
commit 7dad8f6a51
+29 -1
View File
@@ -195,7 +195,10 @@ while true; do
case "$POLL" in
*access_token*)
# Never echo the token; pipe it straight into gh.
echo "$POLL" | sed 's/.*"access_token":"\([^"]*\)".*/\1/' | gh auth login --with-token
# timeout guards the headless-keyring hang (see pitfall below) —
# on exit 124, fall back to writing ~/.config/gh/hosts.yml directly.
echo "$POLL" | sed 's/.*"access_token":"\([^"]*\)".*/\1/' | timeout 20 gh auth login --with-token \
|| { echo "WITH_TOKEN_HUNG_OR_FAILED — use the hosts.yml fallback below"; exit 1; }
gh auth setup-git
gh auth status
echo "LOGIN_COMPLETE"; break ;;
@@ -210,6 +213,29 @@ done
Note: on Windows winget installs, gh lands at `/c/Program Files/GitHub CLI` — add it to PATH in the same shell: `export PATH="$PATH:/c/Program Files/GitHub CLI"`.
> **PITFALL (headless Linux): `gh auth login --with-token` can hang forever.**
> On keyring-less/headless boxes (VPS, containers, no dbus session), gh's
> credential storage may block indefinitely waiting on a secret-service
> keyring — even with `--insecure-storage`, and with no output. If the
> command doesn't return within ~20s (wrap it in `timeout 20 …` to detect
> this), skip gh's login machinery and write the credential store directly:
>
> ```bash
> # $TOKEN = the access token from the device flow above (never echo it)
> mkdir -p ~/.config/gh
> LOGIN=$(curl -s -H "Authorization: token $TOKEN" https://api.github.com/user \
> | sed 's/.*"login": *"\([^"]*\)".*/\1/')
> printf 'github.com:\n users:\n %s:\n oauth_token: %s\n git_protocol: https\n oauth_token: %s\n user: %s\n' \
> "$LOGIN" "$TOKEN" "$TOKEN" "$LOGIN" > ~/.config/gh/hosts.yml
> chmod 600 ~/.config/gh/hosts.yml
> gh auth status # reads hosts.yml directly — verifies without the keyring
> gh auth setup-git # wires the git credential helper (does not hang)
> ```
>
> `gh auth status` and `setup-git` read the file store without touching the
> keyring, so they work immediately. Proven on a headless x86_64 VPS
> (gh 2.97.0, Aug 2026) after `--with-token` hung twice.
### Token-Based Login (Headless / SSH Servers)
```bash
@@ -219,6 +245,8 @@ echo "<THEIR_TOKEN>" | gh auth login --with-token
gh auth setup-git
```
If `--with-token` hangs here, use the hosts.yml fallback from the pitfall above.
### Verify
```bash