{"record":{"id":"0abe729094c85754","repo":"jdx/mise","slug":"github-device-authorization-was-denied","errorCode":null,"errorMessage":"GitHub device authorization was denied","messagePattern":"GitHub device authorization was denied","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"src/github/oauth.rs","lineNumber":366,"sourceCode":"                    debug!(\"transient error polling GitHub OAuth token: {err:#}\");\n                    continue;\n                }\n            },\n            Err(err) => {\n                debug!(\"transient error polling GitHub OAuth token: {err:#}\");\n                continue;\n            }\n        };\n\n        match response.error.as_deref() {\n            None => return Ok(response),\n            Some(\"authorization_pending\") => continue,\n            Some(\"slow_down\") => {\n                interval += 5;\n                continue;\n            }\n            Some(\"expired_token\") => bail!(\"GitHub device authorization expired\"),\n            Some(\"access_denied\") => bail!(\"GitHub device authorization was denied\"),\n            Some(error) => {\n                let details = response\n                    .error_description\n                    .unwrap_or_else(|| error.to_string());\n                bail!(\"{details}\");\n            }\n        }\n    }\n}\n\nasync fn refresh_token(cached: &CachedToken) -> Result<Option<CachedToken>> {\n    let Some(refresh_token) = cached.refresh_token.as_deref() else {\n        return Ok(None);\n    };\n    if cached\n        .refresh_expires_at\n        .is_some_and(|exp| exp <= chrono::Utc::now())\n    {","sourceCodeStart":348,"sourceCodeEnd":384,"githubUrl":"https://github.com/jdx/mise/blob/afd2eddd3a50c16190efc1c7e94404b48f72af57/src/github/oauth.rs#L348-L384","documentation":"GitHub's device-flow token endpoint returned error=access_denied: the user (or a policy) explicitly denied the authorization request at github.com/login/device. poll_access_token maps this to 'GitHub device authorization was denied' and aborts; retrying with the same code will never succeed.","triggerScenarios":"poll_access_token receives a token response whose error field equals \"access_denied\" — the user clicked 'I authorize' as deny / canceled, or an org SSO/APP policy blocked the grant for the client_id in settings.github.oauth_client_id.","commonSituations":"User misclicks deny on the device page; user lacks permission for the requested scope in an enterprise/org with restrictive policies; someone else enters the code and denies it.","solutions":["Rerun `mise token github --oauth` and click Authorize (not deny) when prompted.","Verify your GitHub account/organization grants the requested OAuth app; ask an admin if org policy blocks it.","Confirm you are logged into the intended GitHub account in the browser where you enter the code.","If org policy prevents OAuth grants, use a personal access token via GITHUB_TOKEN instead."],"exampleFix":"// before\n# device page: clicked 'Cancel'\n// GitHub device authorization was denied\n\n// after\nmise token github --oauth\n# on github.com/login/device click 'Authorize mise'","handlingStrategy":"try-catch","validationCode":"null","typeGuard":"null","tryCatchPattern":"if let Err(e) = token_async(req).await {\n    if e.to_string().contains(\"was denied\") {\n        eprintln!(\"authorization denied; rerun and click Authorize on github.com/login/device\");\n    }\n}","preventionTips":["Click Authorize (not Cancel/Deny) on the device page.","Ensure the browser session is the intended GitHub account.","Confirm org/SSO policy permits the mise OAuth app before starting the flow.","If policy blocks grants, provision a personal access token via GITHUB_TOKEN."],"tags":["github","oauth","device-flow","authorization-denied"],"backgroundTag":"permission-denied","analyzedSha":"afd2eddd3a50c16190efc1c7e94404b48f72af57","analyzedAt":"2026-09-09T01:38:25.179Z","contentChangedAt":"2026-09-09T01:38:25.179Z","schemaVersion":2},"datasetVersion":"2026-09-14T00:17:10.932Z"}