decolua/9router · error
refresh token is required
Error message
refresh token is required
What it means
buildExternalIdpRefreshParams builds the x-www-form-urlencoded body for refreshing a Kiro external-IdP token via the Microsoft endpoint. The refreshToken argument must be a non-empty string; this guard fires when it is null, undefined, empty, or whitespace. Note this is a distinct message ('refresh token is required') from the importer's 'refresh_token is required'.
Source
Thrown at src/lib/oauth/kiroExternalIdp.js:135
email,
providerSpecificData: {
profileArn,
region,
authMethod: "external_idp",
provider: "CLIProxyAPI",
clientId,
tokenEndpoint,
scope,
},
};
}
export function buildExternalIdpRefreshParams(refreshToken, providerSpecificData = {}) {
const clientId = normalizeString(providerSpecificData.clientId || providerSpecificData.client_id);
const tokenEndpoint = validateMicrosoftTokenEndpoint(providerSpecificData.tokenEndpoint || providerSpecificData.token_endpoint);
const scope = normalizeScope(providerSpecificData.scope || providerSpecificData.scopes);
if (!refreshToken) throw new Error("refresh token is required");
if (!clientId) throw new Error("clientId is required for external_idp refresh");
if (!scope) throw new Error("scope is required for external_idp refresh");
return {
tokenEndpoint,
body: new URLSearchParams({
grant_type: "refresh_token",
client_id: clientId,
refresh_token: refreshToken,
scope,
}),
providerSpecificData: {
...providerSpecificData,
authMethod: "external_idp",
clientId,
tokenEndpoint,
scope,
},View on GitHub (pinned to 90b52e06ff)
Solutions
- Ensure the account was imported through normalizeKiroExternalIdpAuth, which enforces refresh_token presence, so providerSpecificData carries it
- At the call site, read the refresh token from the correct credential field and pass it as the first argument
- If the refresh token was lost/expired, re-run the external IdP login to obtain a new one and re-import
- Guard the call: skip refresh and force re-auth when refreshToken is falsy instead of calling with an empty value
Example fix
// before
const params = buildExternalIdpRefreshParams(account.refreshToken, account.providerSpecificData);
// after
if (!account.refreshToken) {
throw new Error('Kiro account has no refresh token; re-authentication required');
}
const params = buildExternalIdpRefreshParams(account.refreshToken, account.providerSpecificData); Defensive patterns
Strategy: try-catch
Validate before calling
if (typeof refreshToken !== 'string' || !refreshToken.trim()) {
// force re-authentication path instead of attempting refresh
return scheduleReauth(accountId);
} Type guard
function hasRefreshToken(v) {
return typeof v === 'string' && v.trim() !== '';
} Try / catch
try {
const params = buildExternalIdpRefreshParams(account.refreshToken, account.providerSpecificData);
} catch (e) {
if (e.message === 'refresh token is required') {
// credential unusable: mark account and require interactive re-login
markAccountNeedsReauth(account.id);
return;
}
throw e;
} Prevention
- Only create accounts via normalizeKiroExternalIdpAuth, which guarantees a refresh token exists
- Check refreshToken presence when loading accounts and route empty ones to re-auth early
- Persist the refresh token under a stable key so reads never come back undefined
- Treat a lost refresh token as unrecoverable — refresh tokens cannot be regenerated without re-login
When it happens
Trigger: Calling buildExternalIdpRefreshParams(refreshToken, data) with refreshToken undefined/null/"" — typically because the stored account has no refresh token, or the caller read the wrong field from providerSpecificData.
Common situations: A Kiro account imported without a refresh token now reaching its first refresh; refreshToken stored under a different key so the caller passes undefined; a partially completed import that validated access fields but skipped refresh-token checks upstream.
Related errors
- Vertex: failed to refresh access token from ADC JSON (author
- Failed to refresh credentials. Please re-authorize the conne
- refresh_token is required
- clientId is required for external_idp refresh
- scope is required for external_idp refresh
AI-assisted analysis of decolua/9router@90b52e06ff (2026-08-30).
Data as JSON: /api/errors/6772e1a564310c17.
Report an issue: GitHub.