{"record":{"id":"4ebe3e4a5926137d","repo":"docker/cli","slug":"timed-out-waiting-for-device-token","errorCode":null,"errorMessage":"timed out waiting for device token","messagePattern":"timed out waiting for device token","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"warning","filePath":"internal/oauth/api/api.go","lineNumber":50,"sourceCode":"\t// ClientID is the client ID for the application to auth with the tenant.\n\tClientID string\n\t// Scopes are the scopes that are requested during the device auth flow.\n\tScopes []string\n}\n\n// TokenResponse represents the response of the /oauth/token route.\ntype TokenResponse struct {\n\tAccessToken      string  `json:\"access_token\"`\n\tIDToken          string  `json:\"id_token\"`\n\tRefreshToken     string  `json:\"refresh_token\"`\n\tScope            string  `json:\"scope\"`\n\tExpiresIn        int     `json:\"expires_in\"`\n\tTokenType        string  `json:\"token_type\"`\n\tError            *string `json:\"error,omitempty\"`\n\tErrorDescription string  `json:\"error_description,omitempty\"`\n}\n\nvar ErrTimeout = errors.New(\"timed out waiting for device token\")\n\n// GetDeviceCode initiates the device-code auth flow with the tenant.\n// The state returned contains the device code that the user must use to\n// authenticate, as well as the URL to visit, etc.\nfunc (a API) GetDeviceCode(ctx context.Context, audience string) (State, error) {\n\tdata := url.Values{\n\t\t\"client_id\": {a.ClientID},\n\t\t\"audience\":  {audience},\n\t\t\"scope\":     {strings.Join(a.Scopes, \" \")},\n\t}\n\n\tdeviceCodeURL := a.TenantURL + \"/oauth/device/code\"\n\tresp, err := postForm(ctx, deviceCodeURL, strings.NewReader(data.Encode()))\n\tif err != nil {\n\t\treturn State{}, err\n\t}\n\tdefer func() {\n\t\t_ = resp.Body.Close()","sourceCodeStart":32,"sourceCodeEnd":68,"githubUrl":"https://github.com/docker/cli/blob/4f84911bfe8811e9b028e4b1fee8e7510be79387/internal/oauth/api/api.go#L32-L68","documentation":"ErrTimeout, returned by WaitForDeviceToken when the device-code OAuth flow's expiry timer fires before the user completed authentication in their browser. Auth0 grants a limited window (ExpiryDuration from the device-code response) to authorize the device; if that elapses, polling stops and this error is returned.","triggerScenarios":"Initiating a device-code login (e.g. docker login with the OAuth flow), receiving the device code and URL, but not visiting the URL / entering the code before the tenant's expiry window closes. The timeout.C branch at api.go:136-138 fires.","commonSituations":"User stepped away from the terminal; the device code expired before the browser auth completed; slow network or browser delays; the verification URL was not opened in time.","solutions":["Re-initiate the login flow to get a fresh device code and complete browser auth promptly.","Open the verification URL and enter the code immediately after it is displayed.","If expiry is consistently too short, check network connectivity and that the browser can reach the tenant."],"exampleFix":"# before: docker login  # device code shown, user waited too long -> ErrTimeout\n# after:  docker login   # re-run; open the printed URL and authorize within the time window","handlingStrategy":"retry","validationCode":"// Before starting the device flow, you cannot extend the tenant expiry,\n// but you can guard against background contexts that cancel early:\nfunc ensureLoginContext(ctx context.Context) (context.Context, context.CancelFunc) {\n\treturn context.WithTimeout(ctx, 15*time.Minute)\n}","typeGuard":"// Detect the timeout sentinel\nfunc isDeviceTokenTimeout(err error) bool {\n\treturn errors.Is(err, api.ErrTimeout)\n}","tryCatchPattern":"// Re-initiate the device flow on timeout (user-driven retry)\nstate, err := api.GetDeviceCode(ctx, audience)\nif err != nil { return err }\ntok, err := api.WaitForDeviceToken(ctx, state)\nif errors.Is(err, api.ErrTimeout) {\n    // prompt user to retry promptly\n    state, err = api.GetDeviceCode(ctx, audience)\n    if err != nil { return err }\n    tok, err = api.WaitForDeviceToken(ctx, state)\n}\nreturn tok, err","preventionTips":["Open the verification URL and authorize the device immediately after the code is displayed.","Re-run the login flow if the code expires; do not reuse a stale device code.","Ensure the browser can reach the tenant and the user completes auth within the expiry window."],"tags":["oauth","device-flow","authentication","timeout","auth0"],"backgroundTag":null,"analyzedSha":"4f84911bfe8811e9b028e4b1fee8e7510be79387","analyzedAt":"2026-08-07T12:15:29.814Z","contentChangedAt":null,"schemaVersion":2},"datasetVersion":"2026-09-15T23:17:13.987Z"}