decolua/9router · error

refresh_token is required

Error message

refresh_token is required

What it means

A non-empty refresh_token (or refreshToken) is mandatory: without it the stored Kiro credential can never be refreshed and would die at first expiry. The check fires when the field is absent, empty, or whitespace-only after trim.

Source

Thrown at src/lib/oauth/kiroExternalIdp.js:105

  if (!input || typeof input !== "object") {
    throw new Error("CLIProxyAPI auth JSON is required");
  }

  const authMethod = normalizeString(input.auth_method || input.authMethod);
  if (authMethod && authMethod !== "external_idp") {
    throw new Error("Only external_idp Kiro auth is supported by this importer");
  }

  const accessToken = normalizeString(input.access_token || input.accessToken);
  const refreshToken = normalizeString(input.refresh_token || input.refreshToken);
  const clientId = normalizeString(input.client_id || input.clientId);
  const tokenEndpoint = validateMicrosoftTokenEndpoint(input.token_endpoint || input.tokenEndpoint);
  const profileArn = normalizeString(input.profile_arn || input.profileArn);
  const region = normalizeString(input.region) || DEFAULT_REGION;
  const scope = normalizeScope(input.scopes || input.scope);

  if (!accessToken) throw new Error("access_token is required");
  if (!refreshToken) throw new Error("refresh_token is required");
  if (!clientId) throw new Error("client_id is required");
  if (!scope) throw new Error("scopes is required");
  if (!profileArn) throw new Error("profile_arn is required");

  const payload = decodeJwtPayload(accessToken);
  const email = input.email || payload?.email || payload?.preferred_username || payload?.upn || payload?.sub || null;

  return {
    accessToken,
    refreshToken,
    expiresAt: resolveExpiresAt(input),
    email,
    providerSpecificData: {
      profileArn,
      region,
      authMethod: "external_idp",
      provider: "CLIProxyAPI",
      clientId,

View on GitHub (pinned to 90b52e06ff)

Solutions

  1. Include the refresh_token (or refreshToken) field from the CLIProxyAPI auth document
  2. Re-authenticate via the external IdP flow to get a document containing the refresh token
  3. If the source redacts tokens, export with a non-redacting option or copy the token manually from the original store
  4. Never import an access-token-only blob — it will fail here by design

Example fix

// before
{ "access_token": "eyJ..." }
// after
{ "access_token": "eyJ...", "refresh_token": "0.AXoA..." }
Defensive patterns

Strategy: validation

Validate before calling

const rt = auth.refresh_token ?? auth.refreshToken;
if (typeof rt !== 'string' || !rt.trim()) throw new Error('refresh_token missing from Kiro auth');

Type guard

function hasRefreshToken(a) {
  return typeof a === 'object' && a !== null &&
    ['refresh_token', 'refreshToken'].some(k => typeof a[k] === 'string' && a[k].trim() !== '');
}

Try / catch

try {
  normalizeKiroExternalIdpAuth(auth);
} catch (e) {
  if (e.message === 'refresh_token is required') {
    console.error('Source redacted the refresh token; export without redaction or re-login');
  }
  throw e;
}

Prevention

When it happens

Trigger: Auth JSON missing refresh_token/refreshToken; refresh token blanked by a redaction/sanitization step before import; importing a document that only carries a short-lived access token.

Common situations: Exporting auth from a tool that redacts refresh tokens for security; copying only the access token into the JSON; an upstream login flow that stored the refresh token elsewhere.

Understand the failure class

Background: "Missing required field" and "field is required" errors: why libraries reject payloads that omit mandatory fields — this error's family across 20 libraries.

Related errors


AI-assisted analysis of decolua/9router@90b52e06ff (2026-08-30). Data as JSON: /api/errors/2c2454290a4d90ca. Report an issue: GitHub.