From 169bbb16c459a9bb260651967ec6fa9f57afd038 Mon Sep 17 00:00:00 2001 From: i1hwan Date: Sun, 12 Apr 2026 01:55:07 +0900 Subject: [PATCH 1/3] fix(oauth): restore Claude callback defaults Align the built-in Claude OAuth callback default with the known Claude token flow host so the app stops mixing callback identities across login and refresh paths. Ultraworked with [Sisyphus](https://github.com/code-yeongyu/oh-my-openagent) Co-authored-by: Sisyphus --- src/lib/oauth/constants/oauth.ts | 2 +- tests/unit/oauth-providers-config.test.mjs | 1 + 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/src/lib/oauth/constants/oauth.ts b/src/lib/oauth/constants/oauth.ts index d6c3c9127cc..8fba5305961 100644 --- a/src/lib/oauth/constants/oauth.ts +++ b/src/lib/oauth/constants/oauth.ts @@ -13,7 +13,7 @@ export const CLAUDE_CONFIG = { authorizeUrl: "https://claude.ai/oauth/authorize", tokenUrl: "https://console.anthropic.com/v1/oauth/token", redirectUri: - process.env.CLAUDE_CODE_REDIRECT_URI || "https://platform.claude.com/oauth/code/callback", + process.env.CLAUDE_CODE_REDIRECT_URI || "https://console.anthropic.com/oauth/code/callback", scopes: [ "org:create_api_key", "user:profile", diff --git a/tests/unit/oauth-providers-config.test.mjs b/tests/unit/oauth-providers-config.test.mjs index b4a6d162aea..946f5d16030 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://console.anthropic.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); From 75f72b0a5205a02350ff85daff8fca994df1b7c8 Mon Sep 17 00:00:00 2001 From: i1hwan Date: Sun, 12 Apr 2026 01:55:31 +0900 Subject: [PATCH 2/3] fix(auth): include Claude scope in refresh contract Echo Claude's OAuth scopes on the refresh token request so the token endpoint sees the same app identity and grant context as the working Claude auth flow. Ultraworked with [Sisyphus](https://github.com/code-yeongyu/oh-my-openagent) Co-authored-by: Sisyphus --- open-sse/services/tokenRefresh.ts | 2 ++ tests/unit/token-refresh-service.test.mjs | 3 +++ 2 files changed, 5 insertions(+) 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/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 () => { From 77892f818b6785b847e9455d7bbfeba1a4477de1 Mon Sep 17 00:00:00 2001 From: i1hwan Date: Sun, 12 Apr 2026 02:07:06 +0900 Subject: [PATCH 3/3] fix(oauth): align Claude callback with upstream Ultraworked with [Sisyphus](https://github.com/code-yeongyu/oh-my-openagent) Co-authored-by: Sisyphus --- src/lib/oauth/constants/oauth.ts | 2 +- tests/unit/oauth-providers-config.test.mjs | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/src/lib/oauth/constants/oauth.ts b/src/lib/oauth/constants/oauth.ts index 8fba5305961..d6c3c9127cc 100644 --- a/src/lib/oauth/constants/oauth.ts +++ b/src/lib/oauth/constants/oauth.ts @@ -13,7 +13,7 @@ export const CLAUDE_CONFIG = { authorizeUrl: "https://claude.ai/oauth/authorize", tokenUrl: "https://console.anthropic.com/v1/oauth/token", redirectUri: - process.env.CLAUDE_CODE_REDIRECT_URI || "https://console.anthropic.com/oauth/code/callback", + process.env.CLAUDE_CODE_REDIRECT_URI || "https://platform.claude.com/oauth/code/callback", scopes: [ "org:create_api_key", "user:profile", diff --git a/tests/unit/oauth-providers-config.test.mjs b/tests/unit/oauth-providers-config.test.mjs index 946f5d16030..b9f38c7b4d4 100644 --- a/tests/unit/oauth-providers-config.test.mjs +++ b/tests/unit/oauth-providers-config.test.mjs @@ -301,7 +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://console.anthropic.com/oauth/code/callback"); + 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);