@@ -20,6 +20,7 @@ type manager struct {
2020 serverMutex sync.Mutex
2121 redirectURI string
2222 port int
23+ managedServer bool
2324}
2425
2526// NewManager creates a new OAuth manager with optional port configuration
@@ -29,6 +30,7 @@ func NewManager(emitAuthRequired func(serverURL, serverType, status string), opt
2930 resumeAuthorizeOauthFlow : make (chan bool ),
3031 resumeOauthCodeReceived : make (chan string ),
3132 port : 8083 ,
33+ managedServer : true ,
3234 }
3335
3436 // Apply options
@@ -61,6 +63,12 @@ func WithRedirectURI(uri string) ManagerOption {
6163 }
6264}
6365
66+ func WithManagedServer (managed bool ) ManagerOption {
67+ return func (m * manager ) {
68+ m .managedServer = managed
69+ }
70+ }
71+
6472// HandleAuthorizationFlow handles a single OAuth authorization flow
6573func (m * manager ) HandleAuthorizationFlow (ctx context.Context , sessionID string , oauthErr * AuthorizationRequiredError ) error {
6674 m .emitAuthRequired (oauthErr .ServerURL , oauthErr .ServerType , "pending" )
@@ -176,37 +184,41 @@ func (m *manager) performOAuthAuthorization(ctx context.Context, sessionID strin
176184 slog .Warn ("Failed to start callback server, falling back to manual input" , "error" , err )
177185 }
178186
179- // Check if we have a callback server running (either global or our own)
180- if callbackServer := m .getCallbackServer (); callbackServer != nil {
181- slog .Debug ("Using callback server for OAuth authorization" )
182- // Wait for callback from the browser
183- callbackCtx , cancel := context .WithTimeout (ctx , 5 * time .Minute )
184- defer cancel ()
187+ if m .managedServer {
188+ // Check if we have a callback server running (either global or our own)
189+ if callbackServer := m .getCallbackServer (); callbackServer != nil {
190+ slog .Debug ("Using callback server for OAuth authorization" )
191+ // Wait for callback from the browser
192+ callbackCtx , cancel := context .WithTimeout (ctx , 5 * time .Minute )
193+ defer cancel ()
194+
195+ result , err := callbackServer .WaitForCallback (callbackCtx )
196+ if err != nil {
197+ if err == context .DeadlineExceeded {
198+ return fmt .Errorf ("OAuth authorization timed out after 5 minutes" )
199+ }
200+ return fmt .Errorf ("failed to wait for OAuth callback: %w" , err )
201+ }
185202
186- result , err := callbackServer .WaitForCallback (callbackCtx )
187- if err != nil {
188- if err == context .DeadlineExceeded {
189- return fmt .Errorf ("OAuth authorization timed out after 5 minutes" )
203+ if result .Error != "" {
204+ return fmt .Errorf ("OAuth authorization error: %s" , result .Error )
190205 }
191- return fmt .Errorf ("failed to wait for OAuth callback: %w" , err )
192- }
193206
194- if result .Error ! = "" {
195- return fmt .Errorf ("OAuth authorization error: %s" , result . Error )
196- }
207+ if result .Code = = "" {
208+ return fmt .Errorf ("no authorization code received from OAuth callback" )
209+ }
197210
198- if result .Code == "" {
199- return fmt .Errorf ("no authorization code received from OAuth callback" )
200- }
211+ // Verify state parameter matches
212+ receivedState := result .State
213+ if receivedState != state {
214+ slog .Warn ("OAuth state mismatch" , "expected" , state , "received" , receivedState )
215+ }
201216
202- // Verify state parameter matches
203- receivedState := result . State
204- if receivedState != state {
205- slog . Warn ( "OAuth state mismatch" , "expected" , state , "received" , receivedState )
217+ code = result . Code
218+ slog . Debug ( "Received OAuth code via callback server" , "code_present" , code != "" )
219+ } else {
220+ return fmt . Errorf ( "no callback server available for OAuth authorization" )
206221 }
207-
208- code = result .Code
209- slog .Debug ("Received OAuth code via callback server" , "code_present" , code != "" )
210222 } else {
211223 // Fallback to manual input
212224 slog .Debug ("No callback server available, waiting for manual input" )
0 commit comments