()
| 81 | let pendingState: string | null = null |
| 82 | |
| 83 | export function startChatGptOAuthFlow(): { codeVerifier: string; authUrl: string } { |
| 84 | const codeVerifier = generateCodeVerifier() |
| 85 | const codeChallenge = generateCodeChallenge(codeVerifier) |
| 86 | const state = codeVerifier |
| 87 | |
| 88 | pendingCodeVerifier = codeVerifier |
| 89 | pendingState = state |
| 90 | |
| 91 | const authUrl = new URL(CHATGPT_OAUTH_AUTHORIZE_URL) |
| 92 | authUrl.searchParams.set('response_type', 'code') |
| 93 | authUrl.searchParams.set('client_id', CHATGPT_OAUTH_CLIENT_ID) |
| 94 | authUrl.searchParams.set('redirect_uri', CHATGPT_OAUTH_REDIRECT_URI) |
| 95 | authUrl.searchParams.set('code_challenge', codeChallenge) |
| 96 | authUrl.searchParams.set('code_challenge_method', 'S256') |
| 97 | authUrl.searchParams.set('state', state) |
| 98 | authUrl.searchParams.set('scope', 'openid profile email offline_access') |
| 99 | authUrl.searchParams.set('id_token_add_organizations', 'true') |
| 100 | authUrl.searchParams.set('codex_cli_simplified_flow', 'true') |
| 101 | authUrl.searchParams.set('originator', 'codex_cli_rs') |
| 102 | |
| 103 | return { codeVerifier, authUrl: authUrl.toString() } |
| 104 | } |
| 105 | |
| 106 | const CALLBACK_SERVER_TIMEOUT_MS = 5 * 60 * 1000 |
| 107 |
no test coverage detected