fix claude oauth localhost callback

This commit is contained in:
R.D.
2026-04-02 22:14:04 -04:00
parent 86030a0fab
commit d512ab5ddf
2 changed files with 17 additions and 12 deletions

View File

@@ -3,12 +3,12 @@ import { CLAUDE_CONFIG } from "../constants/oauth";
export const claude = {
config: CLAUDE_CONFIG,
flowType: "authorization_code_pkce",
buildAuthUrl: (config, redirectUri, state, codeChallenge) => {
buildAuthUrl: (config, _redirectUri, state, codeChallenge) => {
const params = new URLSearchParams({
code: "true",
client_id: config.clientId,
response_type: "code",
redirect_uri: redirectUri,
redirect_uri: config.redirectUri,
scope: config.scopes.join(" "),
code_challenge: codeChallenge,
code_challenge_method: config.codeChallengeMethod,
@@ -16,7 +16,7 @@ export const claude = {
});
return `${config.authorizeUrl}?${params.toString()}`;
},
exchangeToken: async (config, code, redirectUri, codeVerifier, state) => {
exchangeToken: async (config, code, _redirectUri, codeVerifier, state) => {
let authCode = code;
let codeState = "";
if (authCode.includes("#")) {
@@ -36,7 +36,7 @@ export const claude = {
state: codeState || state,
grant_type: "authorization_code",
client_id: config.clientId,
redirect_uri: redirectUri,
redirect_uri: config.redirectUri,
code_verifier: codeVerifier,
}),
});

View File

@@ -10,17 +10,22 @@ test.afterEach(() => {
globalThis.fetch = originalFetch;
});
test("Claude OAuth provider uses the runtime redirectUri when building the auth URL", () => {
const redirectUri = "http://localhost:43121/callback";
const authUrl = claude.buildAuthUrl(CLAUDE_CONFIG, redirectUri, "state-123", "challenge-456");
test("Claude OAuth provider always uses the configured redirectUri when building the auth URL", () => {
const runtimeRedirectUri = "http://localhost:43121/callback";
const authUrl = claude.buildAuthUrl(
CLAUDE_CONFIG,
runtimeRedirectUri,
"state-123",
"challenge-456"
);
const parsed = new URL(authUrl);
assert.equal(parsed.searchParams.get("redirect_uri"), redirectUri);
assert.equal(parsed.searchParams.get("redirect_uri"), CLAUDE_CONFIG.redirectUri);
assert.equal(parsed.searchParams.get("state"), "state-123");
assert.equal(parsed.searchParams.get("code_challenge"), "challenge-456");
});
test("Claude OAuth provider uses the runtime redirectUri during token exchange", async () => {
test("Claude OAuth provider always uses the configured redirectUri during token exchange", async () => {
let captured = null;
globalThis.fetch = async (url, init = {}) => {
@@ -37,18 +42,18 @@ test("Claude OAuth provider uses the runtime redirectUri during token exchange",
});
};
const redirectUri = "http://localhost:43121/callback";
const runtimeRedirectUri = "http://localhost:43121/callback";
await claude.exchangeToken(
CLAUDE_CONFIG,
"auth-code#state-from-fragment",
redirectUri,
runtimeRedirectUri,
"verifier-123",
"state-from-request"
);
assert.equal(captured.url, CLAUDE_CONFIG.tokenUrl);
assert.equal(captured.method, "POST");
assert.equal(captured.body.redirect_uri, redirectUri);
assert.equal(captured.body.redirect_uri, CLAUDE_CONFIG.redirectUri);
assert.equal(captured.body.code, "auth-code");
assert.equal(captured.body.state, "state-from-fragment");
assert.equal(captured.body.code_verifier, "verifier-123");