Repository navigation
Support GitHub CLI as a GitHub Authentication Mode #4953
Description
User Story
As a developer who authenticates with the GitHub CLI, I want Specify to obtain its GitHub credential from gh automatically so that I do not have to store a token at rest, either in auth.json or in an environment variable.
Background
Specify reads authentication configuration from the user-level ~/.specify/auth.json. It does not read a project-local .specify/auth.json. A provider entry can supply a credential in two ways today:
token: a static value stored in the file.token_env: the name of an environment variable, resolved from the process environment at request time.
token_env avoids a token in the file. For example, GH_TOKEN="$(gh auth token)" specify <command> works today. It still requires the user to export a token into the process environment on every invocation, and users who want no token at rest, including in a shell profile or environment variable, have no automatic option.
Developers who use the GitHub CLI already have a credential managed by gh (OS keychain or gh auth login session). Specify has an azure-cli auth mode that resolves credentials from the Azure CLI on demand. A matching github-cli mode would give GitHub the same behavior and align with the GitHub affinity described in the authentication reference.
The desired configuration:
{
"providers": [
{
"hosts": [
"github.com",
"api.github.com",
"raw.githubusercontent.com",
"codeload.github.com"
],
"provider": "github",
"auth": "github-cli"
}
]
}This replaces the original proposal of general $(command) substitution in token. A dedicated mode runs a fixed command, so configuration cannot cause arbitrary command execution.
Acceptance Criteria
- A provider entry with
"auth": "github-cli"is accepted by theauth.jsonschema and loaded from the user-level~/.specify/auth.json - When a credential is needed, Specify runs
gh auth tokenand sends the trimmed stdout as the bearer token - The command is not run through a shell and is not configurable from
auth.json - The resolved token is cached in memory for the current run, so
ghruns at most once per host per run - The resolved token is not written to disk, logged, or included in error messages
- If
ghis not installed, the request fails with a clear error that names the provider and states that the GitHub CLI was not found - If
ghis installed but not authenticated, the request fails with a clear error that suggestsgh auth login - If
ghexits non-zero, returns empty output, or exceeds a timeout, the request fails with a clear error that does not include command output - For GitHub Enterprise hosts, Specify requests the token for the matching host (for example
gh auth token --hostname <host>) and has documented behavior when a host is not configured ingh - Existing
authmodes (bearer,azure-cli,token,token_env) behave unchanged, and existing tests pass without modification - The authentication documentation includes
github-cliwith the fullauth.jsonexample above and thegh auth loginprerequisite - New tests cover: token resolved from
gh, per-run caching,ghmissing,ghunauthenticated, non-zero exit, empty output, timeout, and token absent from logs and errors
Technical Notes
- Follow the existing
azure-cliimplementation for mode registration, schema validation, and error handling - Spawn
ghwith an argv list and no shell, with a timeout (for example, 10 seconds) and the inherited environment - Memoize per host per run. This keeps the cost at O(h) subprocess spawns for h distinct hosts, not O(r) for r requests
- Redact the token in all log output and exceptions
- Specify reads only the user-level
~/.specify/auth.json, so no project-level trust handling is needed for this mode
Out of Scope
- General-purpose
$(command)substitution intokenor any other field - Reading authentication configuration from a project-local
.specify/auth.json - Credential helpers for tools other than the GitHub CLI
- Persisting the resolved token across runs
Drafted with Claude Code using Claude Sonnet 5.5 in human-supervised interactive mode; issue drafting and revision based on contributor feedback. The author reviewed the content before publishing.
Activity
mnriem commentedon Oct 13, 2026
Thanks for raising this. We agree with the goal of using credentials managed by GitHub CLI without storing another copy of the token, but a couple of assertions about the current behavior need clarification.
Specify does not read authentication configuration from a project-local
.specify/auth.json. It reads only the user-level~/.specify/auth.json. The file also does not need to contain a token: the existingtoken_envfield resolves it from the process environment at request time.For example:
{ \"providers\": [ { \"hosts\": [ \"github.com\", \"api.github.com\", \"raw.githubusercontent.com\", \"codeload.github.com\" ], \"provider\": \"github\", \"auth\": \"bearer\", \"token_env\": \"GH_TOKEN\" } ] }This works today:
We verified this end to end: Specify loaded the user-level configuration, resolved the token from
GH_TOKEN, and sent the expected bearer header. We also verified that placing the same configuration in a project-local.specify/auth.jsonhas no effect.We suspect the intended request is therefore not general command substitution, but making GitHub CLI credential resolution automatic on every Specify invocation. That is a reasonable convenience feature, but we would prefer a dedicated authentication mode over allowing arbitrary
$(command)execution from configuration.A possible configuration would be:
{ \"providers\": [ { \"hosts\": [ \"github.com\", \"api.github.com\", \"raw.githubusercontent.com\", \"codeload.github.com\" ], \"provider\": \"github\", \"auth\": \"github-cli\" } ] }This follows the existing
azure-cliconvention. Specify would invokegh auth tokenwhen the credential is needed, cache the result for the current run, and avoid writing it to disk or including it in logs and errors. The implementation would also need clear handling for a missing or unauthenticatedgh, command failures and timeouts, and GitHub Enterprise host selection.Would you be open to reframing this issue as “Support GitHub CLI as a GitHub authentication mode”, using
auth: \"github-cli\"rather than general-purpose command substitution?karldreher commentedon Oct 14, 2026
Ultimately, yes, this is the intended effect. The goal would be not relying on storing a token at rest, including in an environment variable.
Thank you for your guidance - i will revise this issue based on it.
[-]Support Dynamic Command Substitution for Tokens in .specify/auth.json[/-][+]Support GitHub CLI as a GitHub Authentication Mode[/+]