Skip to content

Add unmanaged mode for oauth flow#830

Merged
dgageot merged 1 commit intodocker:mainfrom
rumpl:remote-oauth
Nov 17, 2025
Merged

Add unmanaged mode for oauth flow#830
dgageot merged 1 commit intodocker:mainfrom
rumpl:remote-oauth

Conversation

@rumpl
Copy link
Copy Markdown
Member

@rumpl rumpl commented Nov 17, 2025

There are now two modes in the oauth flow

  • Managed mode

In this mode, cagent handles, in process, everything oauth related: asking for user consent, starting the oauth callback server, resuming once the flow is done

  • Unmanaged mode

This mode is more for the remote case in cagent, in this mode the remote cagent will only ask for user consent via an elicitation, up to the client to do the oauth flow and send the token back in the elicitation response.


Here is what cagent has to say about the difference in the two modes:

Now I can explain the key differences between handleUnmanagedOAuthFlow and handleManagedOAuthFlow:

Key Differences Between the Two OAuth Flow Functions

handleManagedOAuthFlow (lines 184-285)

This function performs the complete OAuth flow within cagent itself:

  1. Runs a local callback server - Creates and starts a callback server to receive the OAuth redirect
  2. Handles client registration - Attempts dynamic client registration with the OAuth provider
  3. Generates PKCE parameters - Creates state and PKCE verifier for secure authorization
  4. Requests user consent - Calls t.client.requestUserConsent() to get approval from the user
  5. Opens authorization URL - Calls RequestAuthorizationCode() which typically opens the auth URL in a browser
  6. Receives the callback - The local callback server catches the authorization code
  7. Exchanges code for token - Calls ExchangeCodeForToken() to get the access token
  8. Stores and returns - Saves the token and notifies success

Use case: When cagent is running locally and can open a browser, start HTTP servers, and handle the full OAuth dance.

handleUnmanagedOAuthFlow (lines 288-363)

This function delegates the OAuth flow to the client (typically an MCP client like Claude Desktop):

  1. Discovers OAuth metadata - Fetches the same resource and authorization server metadata
  2. Sends elicitation request - Calls t.client.requestElicitation() with OAuth metadata
  3. Waits for client response - The client performs the OAuth flow externally
  4. Receives token from client - Extracts the access_token and other fields from the elicitation response
  5. Stores and returns - Saves the token received from the client

Use case: When cagent is running as an MCP server where it cannot open browsers or run callback servers. The client application handles the OAuth UI and returns the completed token.

Summary Table

Aspect Managed Flow Unmanaged Flow
Who handles OAuth UI cagent (opens browser) Client application
Callback server Yes, runs locally No
Client registration Yes, dynamic registration Client handles it
PKCE Yes, generates verifier Client handles it
Token exchange Yes, exchanges code for token Client returns complete token
User interaction Browser redirect + consent prompt Client's own OAuth UI
Typical scenario Standalone cagent cagent as MCP server

The managed flow is more complex but gives full control, while the unmanaged flow is simpler and delegates responsibility to a more capable client that has better UI capabilities for handling OAuth.

There are now two modes in the oauth flow

- Managed mode

In this mode, cagent handles, in process, everything oauth related:
asking for user consent, starting the oauth callback server, resuming
once the flow is done

- Unmanged mode

This mode is more for the remote case in cagent, in this mode the remote
cagent will _only_ ask for user consent via an elicitation, up to the
client to do the oauth flow and send the token back in the elicitation
response.

Signed-off-by: Djordje Lukic <djordje.lukic@docker.com>
@rumpl rumpl requested a review from a team as a code owner November 17, 2025 11:03
@dgageot dgageot merged commit 2959dc9 into docker:main Nov 17, 2025
5 checks passed
@rumpl rumpl deleted the remote-oauth branch November 18, 2025 22:25
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants