feat(auth): mint Docker tokens from the stored access token - #3935
Open
dgageot wants to merge 4 commits into
Open
feat(auth): mint Docker tokens from the stored access token#3935dgageot wants to merge 4 commits into
dgageot wants to merge 4 commits into
Conversation
Sayt-0
approved these changes
Aug 6, 2026
aheritier
approved these changes
Aug 6, 2026
Docker Desktop's backend API only hands out its own access token — valid for 15 minutes — and never the refresh token behind it, so an expired JWT cannot be renewed: a stuck refresher on Desktop's side leaves every caller with the same dead token. The access token `docker login` (and Desktop's own sign-in) leaves in the credential store is long-lived, and Docker Hub exchanges it for a fresh token with no user interaction. This package owns that exchange: an in-memory token renewed ahead of its expiry, credential re-checks so a logout or an account switch is noticed, a shared cache so sibling processes don't each mint their own, retries for transient failures (honouring Retry-After), a long back-off when the token is refused, issuer and audience validation, and clock-skew correction learned from Hub's Date header so expiry decisions follow the issuer's clock rather than a drifting local one. The access token itself never leaves the process except in the exchange request: the endpoint is pinned to a Docker host, redirects are not followed, and account passwords are never sent. Set DOCKER_AGENT_NO_TOKEN_EXCHANGE to opt out entirely.
Gateway clients are rebuilt for every request and each one asks for a token, so every LLM call used to pay a round-trip to Docker Desktop over its socket: the token is now kept in memory until it nears its expiry. A token that is about to expire counts as unusable — it would die mid-request — and when Desktop has nothing usable to offer, minting from the stored access token comes before nudging Desktop: it needs nothing from Desktop and, unlike a forced refresh, is deterministic. A token Docker refused is never served again, however healthy Desktop believes it to be. GetTokenWithSource reports where a token came from, and the signed-in account is now read from the token's claims when Desktop isn't around to be asked, so DOCKER_USERNAME and DOCKER_EMAIL also resolve on a plain `docker login`.
A 401 from the gateway is a more reliable signal than local expiry arithmetic, which a skewed clock, a stale cache or a revoked session can all get wrong. Gateway-bound clients now forget the rejected token, ask for a fresh one and replay the request once — bodies that cannot be rewound and requests that presented no token are left alone.
`docker agent debug auth` now shows whether the token came from Docker Desktop or was minted from the stored access token — the first thing to know when the gateway rejects it. The doctor issue no longer implies Docker Desktop is the only way to sign in.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Docker Desktop's backend API only hands out its own access token — valid
for 15 minutes — and never the refresh token behind it, so an expired JWT
cannot be renewed: a stuck refresher on Desktop's side leaves every
caller with the same dead token. The access token
docker login(andDesktop's own sign-in) leaves in the credential store is long-lived, and
Docker Hub exchanges it for a fresh token with no user interaction.
This package owns that exchange: an in-memory token renewed ahead of its
expiry, credential re-checks so a logout or an account switch is noticed,
a shared cache so sibling processes don't each mint their own, retries
for transient failures (honouring Retry-After), a long back-off when the
token is refused, issuer and audience validation, and clock-skew
correction learned from Hub's Date header so expiry decisions follow the
issuer's clock rather than a drifting local one.
The access token itself never leaves the process except in the exchange
request: the endpoint is pinned to a Docker host, redirects are not
followed, and account passwords are never sent. Set
DOCKER_AGENT_NO_TOKEN_EXCHANGE to opt out entirely.