← AUTOMATER NEWSROOM

GitHub CLI's Expiring OAuth Tokens Preview: Opt In With --expiring and a Leaked gh Credential Dies in Hours

GitHub CLI v2.103.0 previews opt-in expiring OAuth tokens that gh refreshes automatically, so a leaked credential dies in hours. How to enable it, the git 2.46 caveat, and what breaks.

Comparison diagram: a stolen non-expiring gh OAuth token stays valid until manually revoked, while an opted-in expiring access token dies within hours as gh automatically rotates a refresh token.Comparison diagram: a stolen non-expiring gh OAuth token stays valid until manually revoked, while an opted-in expiring access token dies within hours as gh automatically rotates a refresh token.
GitHub CLI's opt-in expiring OAuth token preview versus today's non-expiring credential. Drawn from the GitHub Changelog entry and the cli/cli v2.103.0 release notes, both published October 21, 2026.

GitHub CLI v2.103.0, released October 21, 2026, ships a credential change operators should plan around: a public-preview, opt-in OAuth login that stores a short-lived access token alongside a rotating refresh token and refreshes itself in the background. GitHub’s changelog announcement puts the payoff plainly: when you opt in, a leaked access token “becomes unusable within hours instead of lasting indefinitely.”

For anyone whose coding agents, CI runners or fleet laptops shell out to gh, that shrinks the exposure window on a credential that today has no expiry at all — and, per the gh auth login manual, may even be sitting in a plain-text file when no system credential store is available. The day-to-day workflow does not change: nothing happens unless you opt in, existing sign-ins and manually supplied tokens keep working exactly as before, and GitHub says expiring credentials are planned to become the default for new sign-ins in a future release. Piloting now is how you avoid being surprised later.

The GitHub Changelog announcement page for opt-in expiring, auto-refreshing OAuth tokens in GitHub CLI, showing the GitHub Blog header, the October 21, 2026 date, the announcement title, the opening paragraph and the table of contents listing Opting in at login.
GitHub Changelog: the publisher's announcement page header with the October 21, 2026 date, the title GitHub CLI: Opt in to expiring, auto-refreshing OAuth tokens, the opening paragraph of the public preview announcement and the table of contents entry Opting in at login. Captured October 21, 2026. · Original source

How to opt in

# One sign-in with expiring credentials (v2.103.0+)
gh auth login --expiring

# Prefer expiring credentials for every future sign-in
gh config set expiring_credentials enabled

# Check whether the credential is refreshable and when it expires
gh auth status

Per the v2.103.0 release notes, both gh auth status and gh auth token automatically refresh the access token when needed, so there is nothing new to run day to day. The gh auth login manual adds one nuance worth knowing before you script around it: --expiring is a preference, not a guarantee. Whether expiring tokens are issued depends on the host and its OAuth app configuration — a host without support issues a normal non-expiring token, and a host configured for them may issue expiring tokens even without the flag. Pass --expiring=false to explicitly request a non-expiring token when the configuration setting is enabled.

The leak math

Today’s gh OAuth token has no expiry. The manual notes that when no system credential store is found, gh falls back to writing the token to a plain text file — exactly the material infostealers and sloppy dotfile backups harvest. Once copied, that token works until someone notices and revokes it by hand.

With expiring credentials, gh keeps two secrets instead of one: an access token that lives for hours, and a refresh token that rotates. A stolen access token dies on its own at expiry. That is the same logic behind the key-migration drill we published for OpenAI’s legacy API key cutoff and the response to the OpenCode breach that exposed stored provider API keys — except here the rotation is automatic and built into the tool.

Flow diagram: opt in with gh auth login --expiring or the expiring_credentials config; gh stores an hours-lived access token plus a rotating refresh token, kept in the system credential store when one is available and otherwise in a plain-text file, and refreshes automatically; git over HTTPS keeps working via gh auth setup-git, scripts caching gh auth token break, and GH_TOKEN/GITHUB_TOKEN environment tokens are never refreshed.Flow diagram: opt in with gh auth login --expiring or the expiring_credentials config; gh stores an hours-lived access token plus a rotating refresh token, kept in the system credential store when one is available and otherwise in a plain-text file, and refreshes automatically; git over HTTPS keeps working via gh auth setup-git, scripts caching gh auth token break, and GH_TOKEN/GITHUB_TOKEN environment tokens are never refreshed.
The expiring-token workflow and its failure modes, including that gh keeps the two secrets in the system credential store when one is available and otherwise falls back to a plain-text file; compiled from the GitHub Changelog entry, the gh auth login manual and the cli/cli v2.103.0 release notes (October 21, 2026).

Git over HTTPS: two commands, one version floor

If git authenticates over HTTPS, GitHub strongly recommends two things:

gh auth setup-git   # make gh the git credential helper
git --version       # 2.46 or newer recommended

With gh as the credential helper, it serves and refreshes the credential for git, so pushes and clones keep working. Git 2.46 matters because it lets gh mark expiring credentials so they are not cached past their lifetime; on older git, gh still works but prints a one-time upgrade recommendation, and the manual warns that an older credential caching helper may store and reuse an expired token. If your agents clone over HTTPS, pair this with our git HTTPS authentication playbook for agent CI so every clone path is covered.

What breaks: anything that hoards gh auth token

The changelog’s “things to watch out for” section is the real migration guide:

Pattern Under expiring tokens
Running gh commands directly Works; refresh is automatic
Git over HTTPS with gh auth setup-git Works; gh serves a fresh credential
Scripts or extensions that store the output of gh auth token Break at expiry; call gh auth token fresh each time
Tokens supplied through GH_TOKEN / GITHUB_TOKEN Unchanged; the release notes say these are never refreshed, so Actions using github.token are unaffected
gh auth login --with-token with a classic PAT Unchanged; manually supplied tokens work exactly as before

Grep your automation and your installed gh extensions for anything that captures gh auth token once and reuses the value — wrappers, upload scripts, chat-ops bots. The fix is mechanical: read the token at the point of use. If a workflow genuinely depends on a long-lived token, GitHub’s advice is to hold off on opting in for that workflow.

Host support

Expiring tokens are available on github.com and ghe.com today. GitHub Enterprise Server issues them starting with GHES 3.23; on earlier versions, opting in falls back cleanly to today’s non-expiring behavior.

A week-one checklist

  1. Upgrade to gh v2.103.0 and confirm with gh --version.
  2. Pilot on one machine: gh auth login --expiring, then verify gh auth status reports a refreshable credential and shows when the current access token expires (this release also adds a relative time-to-expiry display).
  3. Run gh auth setup-git on every HTTPS host and move git to 2.46 or newer.
  4. Audit scripts and extensions for cached gh auth token values; switch to per-run reads.
  5. Leave CI environment-variable auth alone — those tokens are never refreshed and are therefore unaffected.
  6. Pick a date to flip expiring_credentials enabled fleet-wide, before the default flips for you.

Longer term, this is the same direction as our argument for treating every agent as a service principal: credentials with lifetimes beat credentials with good intentions. The preview is opt-in, the fallback is clean, and the biggest risk this week is a script you forgot caches a token — worth finding now rather than after the default changes.

Sources

  1. GitHub CLI: Opt in to expiring, auto-refreshing OAuth tokens - GitHub Changelog
  2. GitHub CLI | Take GitHub to the command line
  3. Releases · cli/cli · GitHub