Hacktoberfest 2026: the issues maintainers tagged for October, open and beginner-friendly. Browse Hacktoberfest issues

Kiro: dead refresh token (400 invalid_request) never flags needsReauth — dashboard keeps "Logged in" with no re-auth button

Closed
#6,701 1 comment 0 reactions 0 assignees View on GitHub

Maintainers usually reply within 1 day

Nobody has claimed this yet.

Assessment

Difficulty
3/5
Estimated time
Half a day
Newbie friendliness
78/100
Issue type
Bug
Clarity
Clearly specified
Activity status
Active
Tech stack
typescript

Research direction

Start in src/oauth/kiro.ts at KIRO_TERMINAL_REFRESH_ERRORS, then read terminal() and publicOAuthAuthenticationErrorMessage() in src/oauth/index.ts to see why a 400 invalid_request never marks the account. Add the error classification so a dead Kiro refresh token sets needsReauth (or maps to the verify_account reauth reason), and check the provider overview rendering driven by GET /api/oauth/status so an expired expiresAt is not shown as green "Logged in". Done when replaying the 400 invalid_request refresh flips the dashboard to "Needs attention" with a Re-authenticate button; locate the existing terminal refresh-error tests first and run them.

Written by the indexing model from the issue text.

Description

account-pool bug gui
Client or integration

OpenCodex dashboard

Area

Authentication and account pool

Summary

When a Kiro refresh token becomes irredeemable (AWS SSO OIDC no longer accepts it), the account is never flagged needsReauth. The dashboard keeps showing Kiro as Ready / Connected / Logged in with no Re-authenticate button, and every request fails 401 with the generic fallback message. I expected the provider card to flip to "Needs attention" with the Re-authenticate button (or at least the specific "Not logged in to kiro. Run: ocx login kiro" message), like the terminal refresh-error path already produces.

Likely root cause (read from the installed 2.78.0 package):

  • KIRO_TERMINAL_REFRESH_ERRORS in src/oauth/kiro.ts covers only invalid_grant, refresh_token_reused, revoked, revoked_token, refresh_token_revoked, access_denied, expired_token.
  • The dead credential gets a consistent HTTP 400 from oidc..amazonaws.com/token with not in that set.
    {"error":"invalid_request","error_description":"Invalid request","location":null,"reason":null}
    
  • terminal() in src/oauth/index.ts treats KiroTokenRefreshError as terminal only when a 400/401 carries one of the known oauthError values, so the account is never marked; the raw error then surfaces through publicOAuthAuthenticationErrorMessage() as the generic "OAuth authentication failed." text.

Evidence:

  • Stored credential expired at 2026-10-06T10:50:38Z; tested at 2026-10-07T03:34Z.

  • GET /api/oauth/status?provider=kiro still returns loggedIn: true with that expired expiresAt and no needsReauth flag.

  • Client error on every request: "unexpected status 401 Unauthorized: OAuth authentication failed. Check the OpenCodex account status and retry."

  • Replaying the exact refresh request the proxy sends (same registered clientId/clientSecret, same refreshToken) returns HTTP 400 invalid_request.

  • The stored refresh token is identical to the local kiro-cli session token, whose access token is also expired. Only a fresh browser login restores access; no refresh path can.

Reproduction
  1. Import/complete a Kiro login (kiro-cli device/Builder ID flow), then let both the access token and the refresh grant go stale (e.g. leave it idle for a day).
  2. Send any request routed to the kiro provider, e.g. POST /v1/responses with model: kiro/.
  3. Observe the 401 generic OAuth message; dashboard Providers -> Kiro still shows Connected / Logged in with no Re-authenticate button, and Current account usage shows "Failed to refresh quotas".
  4. Manually POST the same refresh payload (grantType: refresh_token, clientId, clientSecret, refreshToken) to https://oidc.<region>.amazonaws.com/token and observe 400 invalid_request.
Version

2.78.0

Operating system

Ubuntu 26.04.1 LTS

Provider and model

kiro / claude-opus-5.5 (any Kiro model; the failure happens at the auth/token-resolution stage)

Logs or error output
[opencodex] OAuth refresh started provider=kiro account=account-…55fe

That line repeats roughly 40 times over an hour (request failures and quota probes keep re-attempting refresh); the credential never rotates and the account is never flagged.

ocx logs --provider kiro --limit 3 --json (redacted row fields):

    {
      "status": 401,
      "durationMs": 40,
      "errorCode": "invalid_api_key",
      "failureStage": "headers-only",
      "failureCause": "credential-rejected",
      "resendPermission": "permitted-after-repair",
      "upstreamError": "OAuth authentication failed. Check the OpenCodex account status and retry."
    }

AWS token endpoint replay (same registered client + stored refresh token as the proxy uses):

    HTTP 400
    {"error":"invalid_request","error_description":"Invalid request","location":null,"reason":null}
Screenshots and supporting files

Dashboard screenshot showing Kiro "Connected / Logged in" plus "Failed to refresh quotas" while all Kiro requests 401; client screenshot of the generic 401 error.

Redacted configuration
{
  "providers": {
    "kiro": {
      "adapter": "kiro",
      "authMode": "oauth",
      "baseUrl": "https://runtime.us-east-1.kiro.dev",
      "defaultModel": "kiro-auto"
    }
  },
  "tokenGuardian": null
}

Note: tokenGuardian is unset (defaults off) and Kiro's default refresh policy is lazy-only, so nothing proactively probes. But even a manual request never sets needsReauth either, because the 400 invalid_request response is not classified as terminal. A UI-level fix would also work: /api/oauth/status already returns expiresAt, and still renders a green "Logged in" for tokens that expired a day+ ago.

Suggested fix (either or both): treat the Kiro SSO 400 invalid_request refresh rejection as terminal (or map it to the verify_account reauth reason), and/or render token-expired state from expiresAt in the provider overview instead of a permanent healthy "Logged in".

Redacted configuration

Checks
  • I searched existing issues and documentation.
  • I removed secrets, tokens, account details, request credentials, and personal data.
Dominant language
TypeScript
Stars
16.9k
Forks
1.3k
Avg merge
4h 52m
Merged PRs (30d)
609

Getting set up

This project ships no dev container, Dockerfile or contributing guide, so setting up is up to you: start from its README, and see our first-contribution guide for the general steps.

First steps

  1. Read the whole issue, then the project's contributing guide.
  2. Comment on the issue to say you are picking it up — it saves two people doing the same work.
  3. Fork the repository and make your change on a branch.
  4. Open a pull request that references the issue number.

More from lidge-jun/opencodex

All issues in lidge-jun/opencodex

Similar issues

More TypeScript issues

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.