decolua/9router · error

Failed to start device authorization: ${error}

Error message

Failed to start device authorization: ${error}

What it means

Thrown by KiroService.startDeviceAuthorization when the AWS SSO OIDC device_authorization endpoint returns non-2xx. The response body (AWS error JSON) is embedded in the message. This step creates the deviceCode/userCode pair, so failure aborts the Builder ID / IDC device login before the user ever sees a verification URL.

Source

Thrown at src/lib/oauth/services/kiro.js:71

  async startDeviceAuthorization(clientId, clientSecret, startUrl, region = "us-east-1") {
    assertValidAwsRegion(region);
    const endpoint = `https://oidc.${region}.amazonaws.com/device_authorization`;

    const response = await fetch(endpoint, {
      method: "POST",
      headers: {
        "Content-Type": "application/json",
      },
      body: JSON.stringify({
        clientId,
        clientSecret,
        startUrl,
      }),
    });

    if (!response.ok) {
      const error = await response.text();
      throw new Error(`Failed to start device authorization: ${error}`);
    }

    const data = await response.json();
    return {
      deviceCode: data.deviceCode,
      userCode: data.userCode,
      verificationUri: data.verificationUri,
      verificationUriComplete: data.verificationUriComplete,
      expiresIn: data.expiresIn,
      interval: data.interval || 5,
    };
  }

  /**
   * Poll for token using device code (AWS Builder ID/IDC)
   */
  async pollDeviceToken(clientId, clientSecret, deviceCode, region = "us-east-1") {
    assertValidAwsRegion(region);

View on GitHub (pinned to 90b52e06ff)

Solutions

  1. Call registerClient again to obtain fresh clientId/clientSecret and retry — expired client secrets are the most common cause.
  2. Check the error body in the message for invalid_client / invalidRequest details.
  3. Ensure the same region is used for registerClient and startDeviceAuthorization.
  4. Back off and retry if the body shows throttling.

Example fix

// before: reusing long-lived cached client creds
await svc.startDeviceAuthorization(saved.clientId, saved.clientSecret, startUrl);
// after: re-register when the client secret expired
const client = saved.clientSecretExpiresAt > Date.now()/1000
  ? saved
  : await svc.registerClient(region);
await svc.startDeviceAuthorization(client.clientId, client.clientSecret, startUrl, region);
Defensive patterns

Strategy: retry

Validate before calling

function hasClientCreds(c) {
  return typeof c?.clientId === 'string' && c.clientId.length > 0 &&
         typeof c?.clientSecret === 'string' && c.clientSecret.length > 0 &&
         (!c.clientSecretExpiresAt || c.clientSecretExpiresAt * 1000 > Date.now());
}
if (!hasClientCreds(saved)) throw new Error('Client credentials missing or expired — call registerClient first');

Type guard

function isDeviceAuthResult(d) { return typeof d?.deviceCode === 'string' && typeof d?.userCode === 'string' && typeof d?.verificationUri === 'string'; }

Try / catch

try {
  return await svc.startDeviceAuthorization(clientId, clientSecret, startUrl, region);
} catch (e) {
  if (/invalid_client|expired/i.test(e.message)) {
    const c = await svc.registerClient(region);
    return svc.startDeviceAuthorization(c.clientId, c.clientSecret, startUrl, region);
  }
  throw e;
}

Prevention

When it happens

Trigger: POST to oidc.<region>.amazonaws.com/device_authorization with clientId/clientSecret/startUrl returns !response.ok — most often an invalid or expired clientId/clientSecret from a previous registerClient, or an unknown region.

Common situations: Reusing cached client credentials after their clientSecretExpiresAt passed; registerClient previously failed partially and stale credentials were persisted; region mismatch between registration and device-authorization calls; AWS 429 throttling.

Related errors


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