fix(cliproxy): harden kiro device-code auth flow consistency

This commit is contained in:
Tam Nhu Tran committed 2026-02-14 10:55:14 +07:00
1 parent 84e0bce99e
commit 826a42d8d6
9 files changed
+122 -43

No files matched your search

+2 -2
View File
@@ -15,19 +15,19 @@ import { AccountInfo } from '../account-manager';
* - Gemini: Authorization Code Flow with local callback server on port 8085
* - Codex: Authorization Code Flow with local callback server on port 1455
* - Agy: Authorization Code Flow with local callback server on port 51121
* - Kiro: Authorization Code Flow with local callback server on port 9876
* - iFlow: Authorization Code Flow with local callback server on port 11451
* - Claude: Authorization Code Flow with local callback server on port 54545 (Anthropic OAuth)
* - Kiro: Device Code Flow (polling-based, NO callback port needed)
* - Qwen: Device Code Flow (polling-based, NO callback port needed)
* - GHCP: Device Code Flow (polling-based, NO callback port needed)
*/
export const OAUTH_CALLBACK_PORTS: Partial<Record<CLIProxyProvider, number>> = {
gemini: 8085,
kiro: 9876,
codex: 1455,
agy: 51121,
iflow: 11451,
claude: 54545,
// kiro: Device Code Flow - no callback port
// qwen: Device Code Flow - no callback port
// ghcp: Device Code Flow - no callback port
};
+28 -24
View File
@@ -9,7 +9,7 @@
* - Codex: 1455
* - Agy: 51121
* - iFlow: 11451
* - Kiro: 9876
* - Kiro: Device Code Flow (no port needed)
* - Claude: 54545
* - Qwen: Device Code Flow (no port needed)
* - GHCP: Device Code Flow (no port needed)
@@ -26,40 +26,44 @@ import {
} from '../utils/port-utils';
import { CLIProxyProvider } from '../cliproxy/types';
import { CLIPROXY_PROFILES } from '../auth/profile-detector';
import {
CLIPROXY_PROVIDER_IDS,
getOAuthCallbackPort,
getOAuthFlowType,
type OAuthFlowType as ProviderOAuthFlowType,
} from '../cliproxy/provider-capabilities';
/**
* OAuth callback ports for each provider
* Extracted from CLIProxyAPI source
* Build provider-indexed records from canonical provider capabilities.
* Keeps diagnostics in sync with runtime OAuth flow metadata.
*/
export const OAUTH_CALLBACK_PORTS: Record<CLIProxyProvider, number | null> = {
gemini: 8085,
codex: 1455,
agy: 51121,
qwen: null, // Device Code Flow - no callback port
iflow: 11451, // Authorization Code Flow
kiro: 9876, // Authorization Code Flow
ghcp: null, // Device Code Flow - no callback port
claude: 54545, // Authorization Code Flow (Anthropic OAuth)
};
function buildProviderMap<T>(
valueFor: (provider: CLIProxyProvider) => T
): Record<CLIProxyProvider, T> {
return CLIPROXY_PROVIDER_IDS.reduce(
(acc, provider) => {
acc[provider] = valueFor(provider);
return acc;
},
{} as Record<CLIProxyProvider, T>
);
}
export const OAUTH_CALLBACK_PORTS: Record<CLIProxyProvider, number | null> = buildProviderMap(
(provider) => getOAuthCallbackPort(provider)
);
/**
* OAuth flow types
*/
export type OAuthFlowType = 'authorization_code' | 'device_code';
export type OAuthFlowType = ProviderOAuthFlowType;
/**
* OAuth flow type per provider
*/
export const OAUTH_FLOW_TYPES: Record<CLIProxyProvider, OAuthFlowType> = {
gemini: 'authorization_code',
codex: 'authorization_code',
agy: 'authorization_code',
qwen: 'device_code',
iflow: 'authorization_code',
kiro: 'authorization_code',
ghcp: 'device_code',
claude: 'authorization_code',
};
export const OAUTH_FLOW_TYPES: Record<CLIProxyProvider, OAuthFlowType> = buildProviderMap(
(provider) => getOAuthFlowType(provider)
);
/**
* Port diagnostic result
@@ -38,6 +38,7 @@ import {
CLIPROXY_CALLBACK_PROVIDER_MAP,
CLIPROXY_AUTH_URL_PROVIDER_MAP,
} from '../../cliproxy/auth/auth-types';
import { getOAuthFlowType } from '../../cliproxy/provider-capabilities';
import type { CLIProxyProvider } from '../../cliproxy/types';
import { CLIPROXY_PROFILES } from '../../auth/profile-detector';
@@ -46,6 +47,13 @@ const router = Router();
// Valid providers list - derived from canonical CLIPROXY_PROFILES
const validProviders: CLIProxyProvider[] = [...CLIPROXY_PROFILES];
export function getStartUrlUnsupportedReason(provider: CLIProxyProvider): string | null {
if (getOAuthFlowType(provider) === 'device_code') {
return `Provider '${provider}' uses Device Code flow. Use /api/cliproxy/auth/${provider}/start instead.`;
}
return null;
}
/**
* GET /api/cliproxy/auth - Get auth status for built-in CLIProxy profiles
* Also fetches CLIProxyAPI stats to update lastUsedAt for active providers
@@ -557,6 +565,11 @@ router.post('/:provider/start-url', async (req: Request, res: Response): Promise
res.status(400).json({ error: `Invalid provider: ${provider}` });
return;
}
const unsupportedReason = getStartUrlUnsupportedReason(provider as CLIProxyProvider);
if (unsupportedReason) {
res.status(400).json({ error: unsupportedReason });
return;
}
try {
const authUrlProvider =