mirror of
https://github.com/Nezumi-2711/9router.git
synced 2026-09-22 13:38:31 +00:00
fix(kiro): route IdC auth to regional CodeWhisperer surface (#2297)
IAM Identity Center (authMethod=idc) tokens failed every request with 403 "bearer token invalid". Treat idc like api_key/external_idp: - executors/kiro.js: route idc to *.amazonaws.com CodeWhisperer surface, region-aware from credentials.region instead of hardcoded us-east-1. - openai-to-kiro.js / claude-to-kiro.js: send resolved profileArn or empty for idc/external_idp, never the shared builder-id placeholder ARN. Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
committed by
decolua
co-authored by
Cursor
parent
9102c4c6d8
commit
abc0add031
@@ -64,9 +64,22 @@ export class KiroExecutor extends BaseExecutor {
|
|||||||
getOrderedBaseUrls(credentials) {
|
getOrderedBaseUrls(credentials) {
|
||||||
const baseUrls = this.getBaseUrls();
|
const baseUrls = this.getBaseUrls();
|
||||||
const authMethod = credentials?.providerSpecificData?.authMethod;
|
const authMethod = credentials?.providerSpecificData?.authMethod;
|
||||||
const isCodeWhispererSurface = authMethod === "api_key" || authMethod === "external_idp";
|
// IAM Identity Center (idc) tokens are AWS SSO access tokens — the same
|
||||||
|
// family as external_idp/api_key. The kiro.dev gateway rejects them with
|
||||||
|
// 403 "bearer token invalid", so they must hit the CodeWhisperer
|
||||||
|
// *.amazonaws.com surface, and in the region the token was minted in
|
||||||
|
// (the baseUrls are hardcoded us-east-1).
|
||||||
|
const isCodeWhispererSurface =
|
||||||
|
authMethod === "api_key" || authMethod === "external_idp" || authMethod === "idc";
|
||||||
if (!isCodeWhispererSurface) return baseUrls;
|
if (!isCodeWhispererSurface) return baseUrls;
|
||||||
const amazon = baseUrls.filter((u) => u.includes("amazonaws.com"));
|
|
||||||
|
const region = (credentials?.providerSpecificData?.region || "us-east-1").trim();
|
||||||
|
const regionalize = (u) =>
|
||||||
|
region && region !== "us-east-1" && u.includes("amazonaws.com")
|
||||||
|
? u.replace(/([a-z]+)\.[a-z0-9-]+\.amazonaws\.com/, `$1.${region}.amazonaws.com`)
|
||||||
|
: u;
|
||||||
|
|
||||||
|
const amazon = baseUrls.filter((u) => u.includes("amazonaws.com")).map(regionalize);
|
||||||
const others = baseUrls.filter((u) => !u.includes("amazonaws.com"));
|
const others = baseUrls.filter((u) => !u.includes("amazonaws.com"));
|
||||||
return amazon.length > 0 ? [...amazon, ...others] : baseUrls;
|
return amazon.length > 0 ? [...amazon, ...others] : baseUrls;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -393,9 +393,12 @@ export function claudeToKiroRequest(model, body, stream, credentials) {
|
|||||||
reconcileOrphanedToolResults(history, currentMessage);
|
reconcileOrphanedToolResults(history, currentMessage);
|
||||||
}
|
}
|
||||||
|
|
||||||
// API-key auth must never use the shared default ARN (403); OAuth/social fall back to it.
|
// api_key / idc / external_idp must never use the shared default ARN (belongs
|
||||||
|
// to another account → 403 "bearer token invalid"); OAuth/social fall back to it.
|
||||||
const authMethod = credentials?.providerSpecificData?.authMethod;
|
const authMethod = credentials?.providerSpecificData?.authMethod;
|
||||||
const profileArn = authMethod === "api_key"
|
const accountBoundAuth =
|
||||||
|
authMethod === "api_key" || authMethod === "idc" || authMethod === "external_idp";
|
||||||
|
const profileArn = accountBoundAuth
|
||||||
? (credentials?.providerSpecificData?.profileArn || "")
|
? (credentials?.providerSpecificData?.profileArn || "")
|
||||||
: (credentials?.providerSpecificData?.profileArn || resolveDefaultProfileArn(authMethod));
|
: (credentials?.providerSpecificData?.profileArn || resolveDefaultProfileArn(authMethod));
|
||||||
|
|
||||||
|
|||||||
@@ -530,8 +530,15 @@ export function openaiToKiroRequest(model, body, stream, credentials) {
|
|||||||
// (the ARN doesn't belong to the key's account). So for api_key, only send a
|
// (the ARN doesn't belong to the key's account). So for api_key, only send a
|
||||||
// profileArn that was actually resolved for this connection — never the default.
|
// profileArn that was actually resolved for this connection — never the default.
|
||||||
// OAuth/social keep the default fallback (their tokens accept it).
|
// OAuth/social keep the default fallback (their tokens accept it).
|
||||||
|
// api_key / idc / external_idp carry an account-specific (or token-bound)
|
||||||
|
// profile. The shared builder-id/social default ARN belongs to a different
|
||||||
|
// account and triggers 403 "bearer token invalid", so never fall back to it —
|
||||||
|
// send the resolved ARN, or an empty string so CodeWhisperer uses the token's
|
||||||
|
// own default profile. Only OAuth/social keep the shared placeholder.
|
||||||
const authMethod = credentials?.providerSpecificData?.authMethod;
|
const authMethod = credentials?.providerSpecificData?.authMethod;
|
||||||
const profileArn = authMethod === "api_key"
|
const accountBoundAuth =
|
||||||
|
authMethod === "api_key" || authMethod === "idc" || authMethod === "external_idp";
|
||||||
|
const profileArn = accountBoundAuth
|
||||||
? (credentials?.providerSpecificData?.profileArn || "")
|
? (credentials?.providerSpecificData?.profileArn || "")
|
||||||
: (credentials?.providerSpecificData?.profileArn || resolveDefaultProfileArn(authMethod));
|
: (credentials?.providerSpecificData?.profileArn || resolveDefaultProfileArn(authMethod));
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user