{"record":{"id":"0dcaf02cc207387e","repo":"decolua/9router","slug":"token-endpoint-is-required","errorCode":null,"errorMessage":"token_endpoint is required","messagePattern":"token_endpoint is required","errorType":"validation","errorClass":null,"httpStatus":null,"severity":"error","filePath":"src/lib/oauth/kiroExternalIdp.js","lineNumber":16,"sourceCode":"const MICROSOFT_TOKEN_ENDPOINT_HOSTS = new Set([\n  \"login.microsoftonline.com\",\n  \"login.microsoft.com\",\n  \"login.windows.net\",\n]);\n\nconst DEFAULT_REGION = \"us-east-1\";\nconst DEFAULT_EXPIRES_IN = 3600;\n\nfunction normalizeString(value) {\n  return typeof value === \"string\" ? value.trim() : \"\";\n}\n\nexport function validateMicrosoftTokenEndpoint(rawEndpoint) {\n  const tokenEndpoint = normalizeString(rawEndpoint);\n  if (!tokenEndpoint) throw new Error(\"token_endpoint is required\");\n\n  let parsed;\n  try {\n    parsed = new URL(tokenEndpoint);\n  } catch {\n    throw new Error(\"token_endpoint must be a valid URL\");\n  }\n\n  if (parsed.protocol !== \"https:\") {\n    throw new Error(\"token_endpoint must use https\");\n  }\n\n  const host = parsed.hostname.toLowerCase();\n  if (!MICROSOFT_TOKEN_ENDPOINT_HOSTS.has(host)) {\n    throw new Error(\"token_endpoint must be a Microsoft login endpoint\");\n  }\n\n  return parsed.toString();","sourceCodeStart":1,"sourceCodeEnd":34,"githubUrl":"https://github.com/decolua/9router/blob/90b52e06ffd666b7929554211474d01588f6b1f8/src/lib/oauth/kiroExternalIdp.js#L1-L34","documentation":"Kiro can use an external Microsoft IdP whose token_endpoint must be supplied/validated. validateMicrosoftTokenEndpoint first requires a non-empty value after trimming; an empty, missing, or whitespace-only token_endpoint throws this error.","triggerScenarios":"Calling tokenEndpoint()/validateMicrosoftTokenEndpoint(undefined), with \"\", or with \"   \" — usually because the IdP discovery document lacked token_endpoint or the stored Kiro external-IdP config omitted the field.","commonSituations":"Misconfigured external IdP in the Kiro account settings where only authorization_endpoint was pasted; a discovery/metadata fetch that returned a partial document; migrating config where the token endpoint field got dropped.","solutions":["Set the token_endpoint on the Kiro external IdP config, e.g. https://login.microsoftonline.com/<tenant>/oauth2/v2.0/token.","Re-fetch the OIDC discovery document (https://login.microsoftonline.com/<tenant>/.well-known/openid-configuration) and copy its token_endpoint value.","If loading from env/config, confirm the variable is set and not whitespace-only."],"exampleFix":"// before\nconst endpoint = process.env.MS_TOKEN_ENDPOINT; // undefined\nvalidateMicrosoftTokenEndpoint(endpoint);\n// after\nconst endpoint = process.env.MS_TOKEN_ENDPOINT ||\n  `https://login.microsoftonline.com/${TENANT_ID}/oauth2/v2.0/token`;\nvalidateMicrosoftTokenEndpoint(endpoint);","handlingStrategy":"validation","validationCode":"const raw = idpConfig.token_endpoint;\nif (typeof raw !== \"string\" || raw.trim() === \"\") {\n  throw new Error(\"External IdP config is missing token_endpoint — copy it from the OIDC discovery document\");\n}\nvalidateMicrosoftTokenEndpoint(raw);","typeGuard":"function hasTokenEndpoint(cfg) {\n  return typeof cfg?.token_endpoint === \"string\" && cfg.token_endpoint.trim().length > 0;\n}","tryCatchPattern":"try {\n  endpoint = tokenEndpoint(idpConfig);\n} catch (err) {\n  if (err.message === \"token_endpoint is required\") {\n    throw new Error(\"Kiro external IdP metadata incomplete: re-fetch openid-configuration\");\n  }\n  throw err;\n}","preventionTips":["Populate IdP config from the discovery document (openid-configuration) instead of hand-typing fields.","Validate the full IdP config at save time so missing token_endpoint is caught early.","When copying config between environments, diff all required fields (issuer, authorization_endpoint, token_endpoint)."],"tags":["oauth","microsoft","validation","missing-config"],"backgroundTag":"missing-required-parameter","analyzedSha":"90b52e06ffd666b7929554211474d01588f6b1f8","analyzedAt":"2026-08-30T21:05:45.952Z","schemaVersion":2},"datasetVersion":"2026-08-30T23:17:21.991Z"}