@@ -77,14 +77,20 @@ type OAuthFlowState = {
7777export interface ProviderHandlerDeps {
7878 authStateStore : IAuthStateStore
7979 browserLauncher : IBrowserLauncher
80+ /** Factory for creating callback servers (injectable for testing) */
8081 createCallbackServer ?: ( options : { callbackPath ?: string ; port : number } ) => ProviderCallbackServer
82+ /** Token exchange function (injectable for testing) */
8183 exchangeCodeForTokens ?: ( params : TokenExchangeParams ) => Promise < ProviderTokenResponse >
84+ /** Copilot token exchange function (injectable for testing) */
8285 exchangeForCopilotToken ?: ( githubToken : string ) => Promise < CopilotTokenResponse >
86+ /** PKCE generator function (injectable for testing) */
8387 generatePkce ?: ( ) => PkceParameters
88+ /** Device flow polling function (injectable for testing) */
8489 pollForAccessToken ?: ( params : PollForAccessTokenParams ) => Promise < string >
8590 providerConfigStore : IProviderConfigStore
8691 providerKeychainStore : IProviderKeychainStore
8792 providerOAuthTokenStore : IProviderOAuthTokenStore
93+ /** Device code request function (injectable for testing) */
8894 requestDeviceCode ?: ( params : RequestDeviceCodeParams ) => Promise < DeviceCodeResponse >
8995 transport : ITransportServer
9096}
@@ -165,18 +171,23 @@ export class ProviderHandler {
165171 tokenUrl : oauthConfig . tokenUrl ,
166172 } )
167173
174+ // Parse JWT id_token for account ID
168175 const oauthAccountId = tokens . id_token ? parseAccountIdFromIdToken ( tokens . id_token ) : undefined
169176
177+ // Store access token as the "API key" in keychain
170178 await this . providerKeychainStore . setApiKey ( providerId , tokens . access_token )
171179
180+ // Store refresh token + expiry in encrypted OAuth token store
172181 if ( tokens . refresh_token ) {
173- const expiresAt = tokens . expires_in ? computeExpiresAt ( tokens . expires_in ) : computeExpiresAt ( 3600 )
182+ const expiresAt = tokens . expires_in ? computeExpiresAt ( tokens . expires_in ) : computeExpiresAt ( 3600 ) // 1-hour default when provider omits expires_in
174183 await this . providerOAuthTokenStore . set ( providerId , {
175184 expiresAt,
176185 refreshToken : tokens . refresh_token ,
177186 } )
178187 }
179188
189+ // Connect provider — secrets stored in keychain + encrypted token store, not config
190+ // OAuth providers may define their own default model (e.g., Codex for OpenAI OAuth)
180191 const defaultModel = oauthConfig . defaultModel ?? providerDef . defaultModel
181192 await this . providerConfigStore . connectProvider ( providerId , {
182193 activeModel : defaultModel ,
@@ -266,6 +277,7 @@ export class ProviderHandler {
266277
267278 return { error : getErrorMessage ( error ) , success : false }
268279 } finally {
280+ // Only clean up if this is still the same flow (guard against concurrent START_OAUTH)
269281 if ( this . oauthFlows . get ( data . providerId ) === flow ) {
270282 await flow . callbackServer ?. stop ( ) . catch ( ( ) => { } )
271283 this . oauthFlows . delete ( data . providerId )
@@ -429,8 +441,10 @@ export class ProviderHandler {
429441 return await this . startDeviceFlow ( data . providerId , oauthConfig , clientId )
430442 }
431443
444+ // Generate PKCE parameters
432445 const pkce = this . generatePkce ( )
433446
447+ // Build auth URL
434448 const mode = oauthConfig . modes . find ( ( m ) => m . id === ( data . mode ?? 'default' ) ) ?? oauthConfig . modes [ 0 ]
435449 const params = new URLSearchParams ( {
436450 client_id : oauthConfig . clientId ,
@@ -442,6 +456,7 @@ export class ProviderHandler {
442456 state : pkce . state ,
443457 } )
444458
459+ // Provider-specific extra params (e.g. OpenAI's codex_cli_simplified_flow)
445460 if ( oauthConfig . extraParams ) {
446461 for ( const [ key , value ] of Object . entries ( oauthConfig . extraParams ) ) {
447462 params . set ( key , value )
@@ -450,19 +465,22 @@ export class ProviderHandler {
450465
451466 const authUrl = `${ mode . authUrl } ?${ params . toString ( ) } `
452467
468+ // Start callback server for auto mode
453469 let callbackServer : ProviderCallbackServer | undefined
454470 if ( oauthConfig . callbackMode === 'auto' && oauthConfig . callbackPort ) {
455471 callbackServer = this . createCallbackServer ( { port : oauthConfig . callbackPort } )
456472 await callbackServer . start ( )
457473 }
458474
475+ // Store flow state
459476 this . oauthFlows . set ( data . providerId , {
460477 callbackServer,
461478 clientId,
462479 codeVerifier : pkce . codeVerifier ,
463480 state : pkce . state ,
464481 } )
465482
483+ // Open browser (non-fatal on failure)
466484 try {
467485 await this . browserLauncher . open ( authUrl )
468486 } catch {
@@ -471,6 +489,7 @@ export class ProviderHandler {
471489
472490 return { authUrl, callbackMode : oauthConfig . callbackMode , success : true }
473491 } catch ( error ) {
492+ // Clean up callback server if it was started but flow setup failed
474493 const partialFlow = this . oauthFlows . get ( data . providerId )
475494 if ( partialFlow ?. callbackServer ) {
476495 await partialFlow . callbackServer . stop ( ) . catch ( ( ) => { } )
0 commit comments