Thanks to visit codestin.com
Credit goes to github.com

Skip to content

Expose external auth token expiry so git credential helpers can set password_expiry_utc #26036

Description

@jasonwbarnett

Summary

Surface the expiry of an external auth token (alongside the token itself) so a git credential helper built on coder external-auth access-token can emit git's password_expiry_utc field. This lets git-credential-cache hold a Coder-minted token for exactly its valid lifetime and evict it the moment it rotates.

Background

In a workspace, git HTTPS auth to GitHub is handled by GIT_ASKPASS pointing at the coder binary (coder gitaskpass), which fetches a token from external auth via the control plane. This is always-fresh and correct, but it costs a control-plane round-trip on every credential request (~0.6-1s in our environment), and git requests credentials twice per HTTPS auth (username + password), so each git fetch / push pays roughly 1-2s of auth overhead.

The natural mitigation is to put git-credential-cache in front of the askpass:

[credential "https://github.com"]
    helper = cache --timeout=900

This is fast, but git-credential-cache only accepts a fixed --timeout and has no knowledge of the token's real lifetime. Because external auth tokens rotate (GitHub App user-to-server tokens last ~8h), a fixed timeout can cache a token that rotates/expires before the timeout elapses. The cache then serves a stale token until the timeout expires, producing intermittent 401s. The worst-case stale window equals the timeout.

Request

Expose the token's expiry so a credential helper can output password_expiry_utc (git >= 2.34). With it, git and git-credential-cache cache the credential for exactly its valid life and re-invoke the helper the instant it expires: fast and correct, with no fixed-timeout guesswork and no stale window.

A helper would emit:

protocol=https
host=github.com
username=x-access-token
password=<token>
password_expiry_utc=<unix-seconds>

The server already tracks the OAuth expiry (oauth_expiry; see coderd/database/queries/externalauth.sql and coderd/externalauth/externalauth.go); it just isn't surfaced to clients. Today:

  • coder external-auth access-token <provider> (cli/externalauth.go) prints only the token. --extra reads the provider's OAuth extra map only; for GitHub it returns no extra properties found for token (cli/externalauth.go:91), and the tracked Expiry isn't reachable.
  • agentsdk.ExternalAuthResponse (codersdk/agentsdk/agentsdk.go:696) carries TokenExtra, URL, Username, Password, but no token expiry.

Any one of these would solve it:

  1. A --expiry flag (or a --format json / password_expiry_utc output mode) on coder external-auth access-token.
  2. Add the expiry to agentsdk.ExternalAuthResponse so coder gitaskpass and credential helpers can read it.

Option 1 alone is enough to build the helper purely client-side.

Why password_expiry_utc

It is git's intended mechanism for short-lived, rotating credentials: a helper returns the credential plus its expiry, git treats it as invalid after that time and re-invokes the helper. The field was added in git 2.34 (see the git-credential documentation). Without an expiry source, users must choose between a slow per-operation askpass and a fixed-timeout cache that has a stale-token window.

Environment

  • Coder v2.33.x (CLI + workspace agent)
  • git 2.43.0
  • GitHub App-based external auth (token rotates ~8h)

Activity

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

Labels

No labels
No labels

Type

No type

Projects

No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions