From 69a80d3ee4e124b8034d147f3169b3fac0407e52 Mon Sep 17 00:00:00 2001 From: diegosouzapw Date: Thu, 21 May 2026 10:54:23 -0300 Subject: [PATCH] fix(kiro): refresh imported social tokens via social-auth, not AWS OIDC (#2467) --- open-sse/services/tokenRefresh.ts | 7 ++-- src/lib/oauth/services/kiro.ts | 6 ++-- tests/unit/token-refresh-service.test.ts | 41 ++++++++++++++++++++++++ 3 files changed, 50 insertions(+), 4 deletions(-) diff --git a/open-sse/services/tokenRefresh.ts b/open-sse/services/tokenRefresh.ts index d22173ec5d..94001479ce 100755 --- a/open-sse/services/tokenRefresh.ts +++ b/open-sse/services/tokenRefresh.ts @@ -611,8 +611,11 @@ export async function refreshKiroToken( const region = providerSpecificData?.region; // AWS SSO OIDC (Builder ID or IDC) - // If clientId and clientSecret exist, assume AWS SSO OIDC (default to builder-id if authMethod not specified) - if (clientId && clientSecret) { + // If clientId and clientSecret exist, assume AWS SSO OIDC (default to builder-id if authMethod not specified). + // Exception: imported social tokens (authMethod === "imported") carry a freshly-registered + // clientId/clientSecret but their refresh token is Kiro-social-issued — the isolated OIDC client + // cannot refresh it, so they must fall through to the social auth path (#2467). + if (clientId && clientSecret && authMethod !== "imported") { const endpoint = `https://oidc.${region || "us-east-1"}.amazonaws.com/token`; const response = await runWithProxyContext(proxyConfig, () => diff --git a/src/lib/oauth/services/kiro.ts b/src/lib/oauth/services/kiro.ts index a399ce7f18..a335d0d1cd 100644 --- a/src/lib/oauth/services/kiro.ts +++ b/src/lib/oauth/services/kiro.ts @@ -184,8 +184,10 @@ export class KiroService { async refreshToken(refreshToken: string, providerSpecificData: any = {}) { const { authMethod, clientId, clientSecret, region } = providerSpecificData; - // AWS SSO OIDC refresh (Builder ID or IDC) - if (clientId && clientSecret) { + // AWS SSO OIDC refresh (Builder ID or IDC). + // Imported social tokens (authMethod === "imported") have a registered clientId/clientSecret + // but a Kiro-social refresh token the OIDC client can't refresh — use the social path (#2467). + if (clientId && clientSecret && authMethod !== "imported") { const endpoint = `https://oidc.${region || "us-east-1"}.amazonaws.com/token`; const response = await fetch(endpoint, { diff --git a/tests/unit/token-refresh-service.test.ts b/tests/unit/token-refresh-service.test.ts index 4727684bdb..143ef92a8a 100644 --- a/tests/unit/token-refresh-service.test.ts +++ b/tests/unit/token-refresh-service.test.ts @@ -589,6 +589,47 @@ test("refreshKiroToken uses AWS OIDC path for social-auth token when clientId is }); }); +// Issue #2467 — an IMPORTED social token (authMethod === "imported") carries a +// freshly-registered clientId/clientSecret, but its refresh token is Kiro-social-issued +// and the isolated OIDC client cannot refresh it. It must use the social-auth endpoint, +// NOT AWS OIDC (which is what #2328 enabled for authMethod "google"). +test("refreshKiroToken uses social-auth path for imported token even with clientId (#2467)", async () => { + const log = createLog(); + const calls: any[] = []; + + await withMockedFetch( + async (url, options = {}) => { + calls.push({ url, options }); + return jsonResponse({ + accessToken: "kiro-imported-access", + refreshToken: "kiro-imported-refresh-next", + expiresIn: 1100, + }); + }, + async () => { + const result = await refreshKiroToken( + "kiro-imported-refresh", + { + authMethod: "imported", + clientId: "isolated-client-id", + clientSecret: "isolated-client-secret", + region: "us-east-1", + }, + log + ); + assert.equal(result.accessToken, "kiro-imported-access"); + } + ); + + // Must call the shared social-auth tokenUrl — NOT the AWS OIDC endpoint. + assert.equal( + calls[0].url, + PROVIDERS.kiro.tokenUrl, + `expected social-auth endpoint but got ${calls[0].url}` + ); + assert.ok(!calls[0].url.includes("oidc."), "imported token must not use AWS OIDC"); +}); + test("refreshQoderToken uses basic auth once qoder oauth settings are configured", async () => { const log = createLog(); const calls: any[] = [];