Skip to content

Support GitHub CLI as a GitHub Authentication Mode #4953

Open

Description

@karldreher

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 the auth.json schema and loaded from the user-level ~/.specify/auth.json
  • When a credential is needed, Specify runs gh auth token and 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 gh runs at most once per host per run
  • The resolved token is not written to disk, logged, or included in error messages
  • If gh is not installed, the request fails with a clear error that names the provider and states that the GitHub CLI was not found
  • If gh is installed but not authenticated, the request fails with a clear error that suggests gh auth login
  • If gh exits 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 in gh
  • Existing auth modes (bearer, azure-cli, token, token_env) behave unchanged, and existing tests pass without modification
  • The authentication documentation includes github-cli with the full auth.json example above and the gh auth login prerequisite
  • New tests cover: token resolved from gh, per-run caching, gh missing, gh unauthenticated, non-zero exit, empty output, timeout, and token absent from logs and errors

Technical Notes

  • Follow the existing azure-cli implementation for mode registration, schema validation, and error handling
  • Spawn gh with 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 in token or 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

  1. mnriem commented on Oct 13, 2026

    @mnriem
    Collaborator

    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 existing token_env field 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:

    GH_TOKEN=\"$(gh auth token)\" specify <command>

    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.json has 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-cli convention. Specify would invoke gh auth token when 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 unauthenticated gh, 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?

    Posted on behalf of @mnriem. Drafted with GitHub Copilot using GPT-5.6 Sol in human-supervised interactive mode; code tracing, end-to-end validation, and issue-response drafting.

  2. karldreher commented on Oct 14, 2026

    @karldreher
    Author
    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.
    

    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.

  3. added
    author-needs-infoMissing detail needed to assess — supply requested info
    triage-out-of-scopeVerdict: won't land in core — invalid, duplicate, off-mission, or redirected to an extension
    triage-can-waitVerdict: valid and in-scope but deprioritized; held behind the evidence gate
    and removed
    triage-out-of-scopeVerdict: won't land in core — invalid, duplicate, off-mission, or redirected to an extension
    on Oct 14, 2026
  4. changed the title [-]Support Dynamic Command Substitution for Tokens in .specify/auth.json[/-] [+]Support GitHub CLI as a GitHub Authentication Mode[/+] on Oct 14, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    author-awaitingWaiting on author responseauthor-needs-infoMissing detail needed to assess — supply requested infotriage-can-waitVerdict: valid and in-scope but deprioritized; held behind the evidence gate

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions