feat(kiro): add external_idp CLIProxyAPI import for Microsoft SSO

Import Kiro accounts authenticated via Microsoft Entra/365 SSO using
CLIProxyAPI JSON. Adds external_idp refresh path (form-encoded OAuth2,
Microsoft login host allowlist), TokenType: EXTERNAL_IDP header for
runtime and usage/quota requests, dashboard import UI, and unit tests.
Scoped to authMethod === "external_idp"; existing Kiro auth unchanged.

Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
Stevanus Pangau
2026-06-26 11:42:05 +07:00
committed by decolua
co-authored by Cursor
parent 49a3ec7a72
commit a4f44e3e12
7 changed files with 554 additions and 5 deletions
+15 -5
View File
@@ -26,7 +26,11 @@ export class KiroExecutor extends BaseExecutor {
// exactly like an OAuth access token, but with an extra `tokentype: API_KEY`
// header so CodeWhisperer treats it as a long-lived API key rather than an
// OIDC/social access token. Mirrors the Kiro IDE headless-auth behavior.
const isApiKey = credentials?.providerSpecificData?.authMethod === "api_key";
// Enterprise / Microsoft Entra (external_idp) tokens are OAuth access tokens,
// but CodeWhisperer requires TokenType=EXTERNAL_IDP to bind them to profiles.
const authMethod = credentials?.providerSpecificData?.authMethod;
const isApiKey = authMethod === "api_key";
const isExternalIdp = authMethod === "external_idp";
const apiKey = credentials?.apiKey || (isApiKey ? credentials?.accessToken : null);
if (isApiKey && apiKey) {
@@ -34,6 +38,9 @@ export class KiroExecutor extends BaseExecutor {
headers["tokentype"] = "API_KEY";
} else if (credentials.accessToken) {
headers["Authorization"] = `Bearer ${credentials.accessToken}`;
if (isExternalIdp) {
headers["TokenType"] = "EXTERNAL_IDP";
}
}
return headers;
@@ -49,13 +56,16 @@ export class KiroExecutor extends BaseExecutor {
* BaseExecutor.execute() returns immediately (only 429 / network errors fall
* through to the next host). So for api-key auth we must try the *.amazonaws.com
* CodeWhisperer hosts FIRST, mirroring the Kiro-Go reference fork which never
* routes api-key traffic through kiro.dev. OAuth keeps the default order
* (kiro.dev first) since its token is what that gateway accepts.
* routes api-key traffic through kiro.dev. External IdP enterprise tokens also
* use the CodeWhisperer surface, with the `TokenType: EXTERNAL_IDP` header.
* Other OAuth methods keep the default order (kiro.dev first) since their
* tokens are what that gateway accepts.
*/
getOrderedBaseUrls(credentials) {
const baseUrls = this.getBaseUrls();
const isApiKey = credentials?.providerSpecificData?.authMethod === "api_key";
if (!isApiKey) return baseUrls;
const authMethod = credentials?.providerSpecificData?.authMethod;
const isCodeWhispererSurface = authMethod === "api_key" || authMethod === "external_idp";
if (!isCodeWhispererSurface) return baseUrls;
const amazon = baseUrls.filter((u) => u.includes("amazonaws.com"));
const others = baseUrls.filter((u) => !u.includes("amazonaws.com"));
return amazon.length > 0 ? [...amazon, ...others] : baseUrls;