{"record":{"id":"94aac96a55432d3e","repo":"Hmbown/CodeWhale","slug":"display-name-offers-no-device-code-flow-sign-in-through-the","errorCode":null,"errorMessage":"{display_name} offers no device-code flow; sign in through the browser login instead","messagePattern":"(.+?) offers no device-code flow; sign in through the browser login instead","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"warning","filePath":"crates/tui/src/oauth.rs","lineNumber":833,"sourceCode":"    let inputs = params.resolve_inputs();\n    let display_name = params.display_name;\n    tokio::task::spawn_blocking(move || device_code_login_with(provider, &inputs))\n        .await\n        .with_context(|| format!(\"{display_name} device-code login worker failed\"))?\n}\n\n/// Blocking worker body for [`device_code_login`]. `pub(crate)` so the\n/// legacy activation tests can drive the unified login end to end until\n/// activation unifies in 3b-ii.\npub(crate) fn device_code_login_with(\n    provider: OAuthProvider,\n    inputs: &ResolvedOAuthInputs,\n) -> Result<PendingOAuthLogin> {\n    let params = oauth_provider_params(provider);\n    let display_name = params.display_name;\n    let endpoints = resolve_oauth_endpoints(params, &inputs.issuer);\n    let Some(device_endpoint) = endpoints.device_authorization_endpoint else {\n        bail!(\n            \"{display_name} offers no device-code flow; sign in through the browser login instead\"\n        );\n    };\n    let token_endpoint = endpoints.token_endpoint;\n    let poll_floor_secs = params.device_poll_floor_secs;\n    let grant = request_device_grant(&device_endpoint, &inputs.client_id, &inputs.scopes)?;\n    let verify = grant\n        .verification_uri_complete\n        .clone()\n        .or(grant.verification_uri.clone())\n        .unwrap_or_else(|| format!(\"{}/device\", inputs.issuer.trim_end_matches('/')));\n    // Off the wire, headed for `webbrowser::open`: must be a bare\n    // navigation, never a scheme or credential smuggle.\n    let verify = codewhale_config::device_code::validate_browser_verification_uri(\n        &verify,\n        &format!(\"{display_name} device-code request\"),\n    )?;\n    let user_code = grant.user_code.unwrap_or_default();","sourceCodeStart":815,"sourceCodeEnd":851,"githubUrl":"https://github.com/Hmbown/CodeWhale/blob/73e0f67d83c59909b571efdfc88c4bc28c309cb1/crates/tui/src/oauth.rs#L815-L851","documentation":"The discovery-time twin of the static guard: even though the provider table lists a device flow, the resolved/discovered endpoint metadata contains no `device_authorization_endpoint`. Thrown in the blocking discovery helper before the grant request is made.","triggerScenarios":"Calling the endpoint-resolution helper when `resolve_oauth_endpoints` returns `device_authorization_endpoint: None` — the issuer's metadata (or configured override) does not advertise a device authorization endpoint.","commonSituations":"Issuer URL pointing at a tenant/instance that does not support device flow (e.g. some SSO tenants disable it); self-hosted identity provider without RFC 8628 enabled; stale cached discovery document.","solutions":["Point the issuer at the correct tenant that supports device authorization","Enable RFC 8628 device flow on your identity provider (e.g. in Keycloak/Auth0/Entra admin settings)","Refresh the discovery metadata (clear cache / correct well-known URL)","Fall back to the browser (PKCE) login"],"exampleFix":null,"handlingStrategy":"fallback","validationCode":"// resolve endpoints first and branch\nconst endpoints = resolveOAuthEndpoints(params, issuer);\nif (!endpoints.device_authorization_endpoint) {\n  return pkceLogin(provider); // discovered metadata lacks device flow\n}","typeGuard":null,"tryCatchPattern":"try {\n  await startDeviceLogin(provider);\n} catch (e) {\n  if (String(e).includes('no device-code flow')) {\n    await pkceLogin(provider);\n  } else { throw e; }\n}","preventionTips":["Verify the issuer tenant has RFC 8628 enabled before advertising device login to users","Refresh cached discovery documents when endpoints come back empty","Test login flows against each issuer/tenant you support"],"tags":["oauth","discovery","device-code"],"backgroundTag":"unsupported-operation","analyzedSha":"73e0f67d83c59909b571efdfc88c4bc28c309cb1","analyzedAt":"2026-09-22T01:30:00.501Z","contentChangedAt":"2026-09-22T01:30:00.501Z","schemaVersion":2},"datasetVersion":"2026-09-23T08:17:48.524Z"}