can1357/oh-my-pi · error · AIError.OAuthError
Authorization was denied
Error message
Authorization was denied
What it means
While polling Kilo's device-code endpoint for approval, an HTTP 403 means the authorization was explicitly denied (or the code was rejected). loginKilo converts this into an OAuthError with kind "device-auth" and this fixed message. Contrast with 202 (still pending) and 410 (expired).
Source
Thrown at packages/ai/src/registry/kilo.ts:70
callbacks.onAuth?.({
url: verificationUrl,
instructions: `Enter code: ${userCode}`,
});
const deadline = Date.now() + expiresInSeconds * 1000;
while (Date.now() < deadline) {
if (callbacks.signal?.aborted) {
throw new AIError.LoginCancelledError();
}
const pollResponse = await fetchImpl(`${KILO_DEVICE_AUTH_BASE_URL}/codes/${encodeURIComponent(userCode)}`);
if (pollResponse.status === 202) {
await Bun.sleep(POLL_INTERVAL_MS);
continue;
}
if (pollResponse.status === 403) {
throw new AIError.OAuthError("Authorization was denied", { kind: "device-auth", provider: "kilo" });
}
if (pollResponse.status === 410) {
throw new AIError.OAuthError("Authorization code expired. Please try again.", {
kind: "device-auth",
provider: "kilo",
});
}
if (!pollResponse.ok) {
throw new AIError.OAuthError(`Failed to poll device authorization: ${pollResponse.status}`, {
kind: "polling",
provider: "kilo",
status: pollResponse.status,
});
}
const pollData = (await pollResponse.json()) as KiloDeviceAuthPollResponse;
if (pollData.status === "approved" && pollData.token) {
return {View on GitHub (pinned to 9690622007)
Solutions
- Restart the login flow (call loginKilo again) to generate a fresh device code and approve it this time.
- Confirm you open the exact verificationUrl shown and approve with the intended account.
- Check for org/security policies or browser extensions blocking the approval action.
- If denials are unexpected, verify the device code was entered correctly and wasn't for someone else's request.
Example fix
// before
await loginKilo(callbacks); // user clicks Deny -> unhandled OAuthError
// after
try {
await loginKilo(callbacks);
} catch (err) {
if (AIError.OAuthError.is(err) && err.message === "Authorization was denied") {
return promptRetry("Authorization denied — start login again to approve.");
}
throw err;
} Defensive patterns
Strategy: try-catch
Try / catch
try {
await loginKilo(callbacks);
} catch (err) {
if (err instanceof AIError.OAuthError && err.message === "Authorization was denied") {
console.error("Login denied on the verification page — run login again and choose Approve.");
return null;
}
throw err;
} Prevention
- Instruct users to click Approve (not Deny) on the verification page.
- Have users verify the user code matches before approving.
- Restart the flow with a fresh code after any denial — codes are single-use for approval decisions.
- Check org policies/browser extensions if approvals are unexpectedly rejected.
When it happens
Trigger: The poll GET `${KILO_DEVICE_AUTH_BASE_URL}/codes/<userCode>` returns status 403 — the user clicked 'Deny' on the verification page, or the server rejects the code/identity at approval time.
Common situations: User denies the request in the browser by mistake or deliberately; the verification page session doesn't match the requesting account; security software or an admin policy blocks approval.
Related errors
- Too many pending authorization requests. Please try again la
- Failed to initiate device authorization: ${initiateResponse.
- Kilo device authorization response missing required fields
- Login cancelled
- Kimi device authorization denied
AI-assisted analysis of can1357/oh-my-pi@9690622007 (2026-08-31).
Data as JSON: /api/errors/8d34bbdb0cb81985.
Report an issue: GitHub.