diff --git a/open-sse/services/tokenRefresh.ts b/open-sse/services/tokenRefresh.ts index ab5cda91009..1f4f1f1ae6b 100755 --- a/open-sse/services/tokenRefresh.ts +++ b/open-sse/services/tokenRefresh.ts @@ -1,3 +1,4 @@ +import { CLAUDE_CONFIG } from "@/lib/oauth/constants/oauth"; import { PROVIDERS, OAUTH_ENDPOINTS } from "../config/constants.ts"; import { pbkdf2Sync } from "node:crypto"; import { runWithProxyContext } from "../utils/proxyFetch.ts"; @@ -226,6 +227,7 @@ export async function refreshClaudeOAuthToken(refreshToken, log, proxyConfig = n grant_type: "refresh_token", refresh_token: refreshToken, client_id: PROVIDERS.claude.clientId, + scope: CLAUDE_CONFIG.scopes.join(" "), }; const makeRequest = (contentType, extraHeaders = {}) => diff --git a/tests/unit/oauth-providers-config.test.mjs b/tests/unit/oauth-providers-config.test.mjs index b4a6d162aea..b9f38c7b4d4 100644 --- a/tests/unit/oauth-providers-config.test.mjs +++ b/tests/unit/oauth-providers-config.test.mjs @@ -301,6 +301,7 @@ test("device and import-token providers expose the flow-specific fields expected }); test("provider-specific config shapes remain valid for special cases", () => { + assert.equal(CLAUDE_CONFIG.redirectUri, "https://platform.claude.com/oauth/code/callback"); assert.ok(Array.isArray(CLAUDE_CONFIG.scopes) && CLAUDE_CONFIG.scopes.length > 0); assert.ok(Array.isArray(GEMINI_CONFIG.scopes) && GEMINI_CONFIG.scopes.length > 0); assert.ok(Array.isArray(ANTIGRAVITY_CONFIG.scopes) && ANTIGRAVITY_CONFIG.scopes.length > 0); diff --git a/tests/unit/token-refresh-service.test.mjs b/tests/unit/token-refresh-service.test.mjs index 07d3c0560a3..afeb8e30407 100644 --- a/tests/unit/token-refresh-service.test.mjs +++ b/tests/unit/token-refresh-service.test.mjs @@ -310,6 +310,8 @@ test("refreshClaudeOAuthToken first matches Claude auth exchange token contract" grant_type: "refresh_token", refresh_token: "claude-refresh", client_id: PROVIDERS.claude.clientId, + scope: + "org:create_api_key user:profile user:inference user:sessions:claude_code user:mcp_servers", }); }); @@ -352,6 +354,7 @@ test("refreshClaudeOAuthToken retries with user-agent JSON then form when format assert.equal(calls[2].options.headers["Content-Type"], "application/x-www-form-urlencoded"); assert.match(calls[2].options.body, /grant_type=refresh_token/); assert.match(calls[2].options.body, /client_id=/); + assert.match(calls[2].options.body, /scope=org%3Acreate_api_key/); }); test("refreshGoogleToken exchanges refresh tokens against the shared google endpoint", async () => {