{"record":{"id":"6e2081ba2807319a","repo":"decolua/9router","slug":"client-id-is-required","errorCode":null,"errorMessage":"client_id is required","messagePattern":"client_id is required","errorType":"validation","errorClass":null,"httpStatus":null,"severity":"error","filePath":"src/lib/oauth/kiroExternalIdp.js","lineNumber":106,"sourceCode":"    throw new Error(\"CLIProxyAPI auth JSON is required\");\n  }\n\n  const authMethod = normalizeString(input.auth_method || input.authMethod);\n  if (authMethod && authMethod !== \"external_idp\") {\n    throw new Error(\"Only external_idp Kiro auth is supported by this importer\");\n  }\n\n  const accessToken = normalizeString(input.access_token || input.accessToken);\n  const refreshToken = normalizeString(input.refresh_token || input.refreshToken);\n  const clientId = normalizeString(input.client_id || input.clientId);\n  const tokenEndpoint = validateMicrosoftTokenEndpoint(input.token_endpoint || input.tokenEndpoint);\n  const profileArn = normalizeString(input.profile_arn || input.profileArn);\n  const region = normalizeString(input.region) || DEFAULT_REGION;\n  const scope = normalizeScope(input.scopes || input.scope);\n\n  if (!accessToken) throw new Error(\"access_token is required\");\n  if (!refreshToken) throw new Error(\"refresh_token is required\");\n  if (!clientId) throw new Error(\"client_id is required\");\n  if (!scope) throw new Error(\"scopes is required\");\n  if (!profileArn) throw new Error(\"profile_arn is required\");\n\n  const payload = decodeJwtPayload(accessToken);\n  const email = input.email || payload?.email || payload?.preferred_username || payload?.upn || payload?.sub || null;\n\n  return {\n    accessToken,\n    refreshToken,\n    expiresAt: resolveExpiresAt(input),\n    email,\n    providerSpecificData: {\n      profileArn,\n      region,\n      authMethod: \"external_idp\",\n      provider: \"CLIProxyAPI\",\n      clientId,\n      tokenEndpoint,","sourceCodeStart":88,"sourceCodeEnd":124,"githubUrl":"https://github.com/decolua/9router/blob/90b52e06ffd666b7929554211474d01588f6b1f8/src/lib/oauth/kiroExternalIdp.js#L88-L124","documentation":"The OAuth client_id (or clientId) of the Microsoft Entra app used for the external IdP flow is required. It is stored in providerSpecificData and replayed in every refresh-token request body (client_id parameter). Missing/empty client_id aborts normalization.","triggerScenarios":"Auth JSON without client_id/clientId, or an empty/whitespace value; hand-building the auth document and omitting the app registration's client id.","commonSituations":"Copying an auth template that doesn't include client_id; mixing fields from two auth files (tokens from one, metadata missing); a CLIProxyAPI version writing snake_case while you only copied camelCase keys (both accepted, but the value must exist under one of them).","solutions":["Add client_id (or clientId) with the Entra application (client) ID GUID from your app registration","Re-export the auth file from the tool that created the login — it should contain client_id","If the app registration is gone, recreate it in Azure and redo the login flow","Confirm the key spelling: only client_id/clientId are recognized"],"exampleFix":"// before\n{ \"access_token\": \"...\", \"refresh_token\": \"...\", \"scopes\": \"openid\" }\n// after\n{ \"access_token\": \"...\", \"refresh_token\": \"...\", \"client_id\": \"04b07795-8ddb-461a-bbee-02f9e1bf7b46\", \"scopes\": \"openid\" }","handlingStrategy":"validation","validationCode":"const cid = auth.client_id ?? auth.clientId;\nif (typeof cid !== 'string' || !cid.trim()) throw new Error('client_id missing from Kiro auth');","typeGuard":"function hasClientId(a) {\n  return typeof a === 'object' && a !== null &&\n    ['client_id', 'clientId'].some(k => typeof a[k] === 'string' && a[k].trim() !== '');\n}","tryCatchPattern":"try {\n  normalizeKiroExternalIdpAuth(auth);\n} catch (e) {\n  if (e.message === 'client_id is required') {\n    console.error('Add the Entra app (client) ID to the auth document');\n  }\n  throw e;\n}","preventionTips":["Copy the whole auth file from CLIProxyAPI instead of reconstructing fields by hand","Record the Entra app registration client id alongside your tokens","Use a schema validator (e.g. zod) for the auth document shape before import","When merging auth files, take all fields from one source document"],"tags":["oauth","missing-field","client-id","entra"],"backgroundTag":"missing-required-field","analyzedSha":"90b52e06ffd666b7929554211474d01588f6b1f8","analyzedAt":"2026-08-30T21:05:45.952Z","schemaVersion":2},"datasetVersion":"2026-08-30T23:17:21.991Z"}