84 lines
2.8 KiB
TypeScript
84 lines
2.8 KiB
TypeScript
import {
|
|
buildCodexAuthorizeUrl,
|
|
createPkcePair,
|
|
extractCodexIdentity,
|
|
renderCodexOauthCallbackHtml,
|
|
} from './codex-oauth';
|
|
|
|
describe('codex-oauth helpers', () => {
|
|
it('builds the OpenAI authorize URL with Codex-specific PKCE parameters', () => {
|
|
const url = new URL(
|
|
buildCodexAuthorizeUrl({
|
|
state: 'state-123',
|
|
codeChallenge: 'challenge-abc',
|
|
redirectUri: 'http://localhost:1455/auth/callback',
|
|
}),
|
|
);
|
|
|
|
expect(url.origin + url.pathname).toBe(
|
|
'https://auth.openai.com/oauth/authorize',
|
|
);
|
|
expect(url.searchParams.get('response_type')).toBe('code');
|
|
expect(url.searchParams.get('client_id')).toBe(
|
|
'app_EMoamEEZ73f0CkXaXp7hrann',
|
|
);
|
|
expect(url.searchParams.get('redirect_uri')).toBe(
|
|
'http://localhost:1455/auth/callback',
|
|
);
|
|
expect(url.searchParams.get('scope')).toBe(
|
|
'openid profile email offline_access',
|
|
);
|
|
expect(url.searchParams.get('code_challenge')).toBe('challenge-abc');
|
|
expect(url.searchParams.get('code_challenge_method')).toBe('S256');
|
|
expect(url.searchParams.get('state')).toBe('state-123');
|
|
expect(url.searchParams.get('originator')).toBe('codex_cli_rs');
|
|
expect(url.searchParams.get('codex_cli_simplified_flow')).toBe('true');
|
|
expect(url.searchParams.get('id_token_add_organizations')).toBe('true');
|
|
});
|
|
|
|
it('creates a valid PKCE verifier/challenge pair', () => {
|
|
const pair = createPkcePair(Buffer.alloc(32, 7));
|
|
|
|
expect(pair.verifier).toBe('BwcHBwcHBwcHBwcHBwcHBwcHBwcHBwcHBwcHBwcHBwc');
|
|
expect(pair.challenge).toBe('3Ev4DHdHPRMPoN6GukAY_pi7IUAF5qWJHRK6kURvnoE');
|
|
});
|
|
|
|
it('extracts account identity fields from the id token payload', () => {
|
|
const header = Buffer.from(JSON.stringify({ alg: 'none' })).toString(
|
|
'base64url',
|
|
);
|
|
const payload = Buffer.from(
|
|
JSON.stringify({
|
|
email: 'operator@example.com',
|
|
exp: 1_800_000_000,
|
|
'https://api.openai.com/auth': {
|
|
chatgpt_account_id: 'acct_123',
|
|
chatgpt_plan_type: 'pro',
|
|
},
|
|
}),
|
|
).toString('base64url');
|
|
const token = `${header}.${payload}.signature`;
|
|
|
|
expect(extractCodexIdentity(token)).toEqual({
|
|
email: 'operator@example.com',
|
|
accountId: 'acct_123',
|
|
planType: 'pro',
|
|
expiresAt: new Date(1_800_000_000 * 1000),
|
|
});
|
|
});
|
|
|
|
it('renders callback html that reports completion back to the frontend window', () => {
|
|
const html = renderCodexOauthCallbackHtml({
|
|
attemptId: 'attempt_123',
|
|
status: 'success',
|
|
frontendOrigin: 'http://localhost:5173',
|
|
message: 'Connected successfully',
|
|
});
|
|
|
|
expect(html).toContain('codexdash:oauth-complete');
|
|
expect(html).toContain('attempt_123');
|
|
expect(html).toContain('Connected successfully');
|
|
expect(html).toContain('http://localhost:5173');
|
|
});
|
|
});
|