fix: route Cursor auth through browser polling

Closes #1194
This commit is contained in:
Kai (Tam Nhu) Tran authored and GitHub committed 2026-05-07 11:25:17 -04:00
1 parent a95266e4cc
commit 8b681df455
12 files changed
+152 -25

No files matched your search

@@ -2,6 +2,7 @@ import { describe, expect, it } from 'bun:test';
import {
buildProviderAliasMap,
CLIPROXY_PROVIDER_IDS,
getDeviceCodeVerificationProviders,
getOAuthCallbackPort,
getOAuthFlowType,
PROVIDER_CAPABILITIES,
@@ -76,6 +77,17 @@ describe('provider-capabilities', () => {
]);
});
it('separates browser URL auth providers from verification-code device flows', () => {
expect(getDeviceCodeVerificationProviders()).toEqual([
'qwen',
'kiro',
'ghcp',
'kimi',
'codebuddy',
'kilo',
]);
});
it('maps external provider aliases to canonical IDs', () => {
expect(mapExternalProviderName('gemini-cli')).toBe('gemini');
expect(mapExternalProviderName('antigravity')).toBe('agy');
@@ -9,9 +9,9 @@ import { CLIPROXY_DEFAULT_PORT as BACKEND_CLIPROXY_DEFAULT_PORT } from '../port-
import { DEFAULT_CURSOR_PORT as BACKEND_CURSOR_DEFAULT_PORT } from '../../../cursor/cursor-models';
import {
CLIPROXY_PROVIDER_IDS as BACKEND_CLIPROXY_PROVIDER_IDS,
getDeviceCodeVerificationProviders,
getProviderDescription as getBackendProviderDescription,
getProviderDisplayName as getBackendProviderDisplayName,
getProvidersByOAuthFlow,
} from '../../provider-capabilities';
import {
CLIPROXY_DEFAULT_PORT as UI_CLIPROXY_DEFAULT_PORT,
@@ -20,9 +20,9 @@ import {
import {
CLIPROXY_PROVIDERS as UI_CLIPROXY_PROVIDERS,
CORE_CLIPROXY_PROVIDERS as UI_CORE_CLIPROXY_PROVIDERS,
DEVICE_CODE_PROVIDERS as UI_DEVICE_CODE_PROVIDERS,
PLUS_EXTRA_CLIPROXY_PROVIDERS as UI_PLUS_EXTRA_CLIPROXY_PROVIDERS,
PROVIDER_METADATA as UI_PROVIDER_METADATA,
VERIFICATION_CODE_AUTH_PROVIDERS as UI_VERIFICATION_CODE_AUTH_PROVIDERS,
} from '../../../../ui/src/lib/provider-config';
import { PLUS_ONLY_PROVIDERS as BACKEND_PLUS_ONLY_PROVIDERS } from '../../types/index';
@@ -43,9 +43,9 @@ describe('Default Port Sync', () => {
expect(sorted(UI_CLIPROXY_PROVIDERS)).toEqual(sorted(BACKEND_CLIPROXY_PROVIDER_IDS));
});
test('Device code providers are synced between backend and UI', () => {
expect(sorted(UI_DEVICE_CODE_PROVIDERS)).toEqual(
sorted(getProvidersByOAuthFlow('device_code'))
test('verification-code auth providers are synced between backend and UI', () => {
expect(sorted(UI_VERIFICATION_CODE_AUTH_PROVIDERS)).toEqual(
sorted(getDeviceCodeVerificationProviders())
);
});
+16
View File
@@ -188,6 +188,12 @@ export const CLIPROXY_PROVIDER_IDS = Object.freeze(
Object.keys(PROVIDER_CAPABILITIES) as CLIProxyProvider[]
);
export const BROWSER_URL_AUTH_PROVIDER_IDS = Object.freeze([
'cursor',
] as const satisfies readonly CLIProxyProvider[]);
const BROWSER_URL_AUTH_PROVIDER_SET = new Set<CLIProxyProvider>(BROWSER_URL_AUTH_PROVIDER_IDS);
/** Providers currently supported by quota status fetchers. */
export const QUOTA_SUPPORTED_PROVIDER_IDS = Object.freeze([
'agy',
@@ -278,6 +284,16 @@ export function getProvidersByOAuthFlow(flowType: OAuthFlowType): CLIProxyProvid
);
}
export function isBrowserUrlAuthProvider(provider: CLIProxyProvider): boolean {
return BROWSER_URL_AUTH_PROVIDER_SET.has(provider);
}
export function getDeviceCodeVerificationProviders(): CLIProxyProvider[] {
return getProvidersByOAuthFlow('device_code').filter(
(provider) => !isBrowserUrlAuthProvider(provider)
);
}
export function getOAuthFlowType(provider: CLIProxyProvider): OAuthFlowType {
return PROVIDER_CAPABILITIES[provider].oauthFlow;
}
@@ -56,7 +56,11 @@ import {
normalizeKiroAuthMethod,
toKiroManagementMethod,
} from '../../cliproxy/auth/auth-types';
import { getOAuthFlowType, mapExternalProviderName } from '../../cliproxy/provider-capabilities';
import {
getOAuthFlowType,
isBrowserUrlAuthProvider,
mapExternalProviderName,
} from '../../cliproxy/provider-capabilities';
import type { CLIProxyProvider } from '../../cliproxy/types';
import { CLIPROXY_PROFILES } from '../../auth/profile-detector';
import {
@@ -286,6 +290,10 @@ export function getStartUrlUnsupportedReason(
return null;
}
if (isBrowserUrlAuthProvider(provider)) {
return null;
}
if (getOAuthFlowType(provider) === 'device_code') {
return `Provider '${provider}' uses Device Code flow. Use /api/cliproxy/auth/${provider}/start instead.`;
}