Skip to content

feat: support Client ID Metadata Document (CIMD) for OAuth#8550

Merged
jh-block merged 5 commits into
mainfrom
jhugo/issue-7071
Apr 15, 2026
Merged

feat: support Client ID Metadata Document (CIMD) for OAuth#8550
jh-block merged 5 commits into
mainfrom
jhugo/issue-7071

Conversation

@jh-block
Copy link
Copy Markdown
Collaborator

Summary

Add CIMD (Client ID Metadata Document) support so Goose can connect to MCP servers that support CIMD-based OAuth (SEP-991) without requiring manual client registration or Dynamic Client Registration.

  • Adds a client metadata JSON document at documentation/static/oauth/client-metadata.json, which will be served at https://goose-docs.ai/oauth/client-metadata.json via the existing docs deployment
  • Switches the OAuth flow to use rmcp's start_authorization_with_metadata_url(), passing the CIMD URL. Servers that support CIMD will use it; others fall back to DCR transparently.

Testing

  • cargo build -p goose compiles successfully
  • cargo test -p goose passes (3 pre-existing unrelated failures)
  • After docs deploy: verify the JSON is served at the expected URL
  • Manual: connect to a CIMD-supporting MCP server and verify OAuth completes

Related Issues

Relates to #7071

Add CIMD support so Goose can connect to MCP servers that support
CIMD-based OAuth without requiring manual client registration or DCR.

- Host a client metadata JSON document that will be served at
  https://goose-docs.ai/oauth/client-metadata.json
- Use rmcp's start_authorization_with_metadata_url() to pass the
  CIMD URL into the OAuth flow, with transparent DCR fallback
Copy link
Copy Markdown

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: d3e85b6ff8

ℹ️ About Codex in GitHub

Codex has been enabled to automatically review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

When you sign up for Codex through ChatGPT, Codex can also answer questions or update the PR, like "@codex address that feedback".

Comment thread documentation/static/oauth/client-metadata.json Outdated
@github-actions
Copy link
Copy Markdown
Contributor

github-actions Bot commented Apr 15, 2026

PR Preview Action v1.8.1
Preview removed because the pull request was closed.
2026-04-15 16:21 UTC

The actual redirect URI sent during the OAuth flow includes
/oauth_callback, so the CIMD document must match. RFC 8252 allows
dynamic ports for loopback, but the path must be consistent.
Copy link
Copy Markdown

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: 2827ff60a0

ℹ️ About Codex in GitHub

Codex has been enabled to automatically review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

When you sign up for Codex through ChatGPT, Codex can also answer questions or update the PR, like "@codex address that feedback".

Comment thread documentation/static/oauth/client-metadata.json Outdated
Per documentation/AGENTS.md brand guidelines, the product name
should always use a lowercase "g".
Copy link
Copy Markdown

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: 9030336842

ℹ️ About Codex in GitHub

Codex has been enabled to automatically review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

When you sign up for Codex through ChatGPT, Codex can also answer questions or update the PR, like "@codex address that feedback".

{
"client_id": "https://goose-docs.ai/oauth/client-metadata.json",
"client_name": "goose",
"redirect_uris": ["http://localhost/oauth_callback"],
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P1 Badge Align metadata redirect URI with runtime callback URI

The OAuth flow sends redirect_uri as http://localhost:{port}/oauth_callback with an ephemeral port (crates/goose/src/oauth/mod.rs line 83), but this metadata document only registers http://localhost/oauth_callback. On authorization servers that enforce exact redirect URI matching for Client ID Metadata Documents, authorization will fail with an invalid redirect URI. Fresh evidence: rmcp’s URL-based client-id path (AuthorizationSession::new in transport/auth.rs, lines 2129-2148 on docs.rs) uses the metadata URL directly when client_id_metadata_document_supported=true and does not fall back to DCR in that branch, so this mismatch is terminal.

Useful? React with 👍 / 👎.

Copy link
Copy Markdown
Collaborator Author

@jh-block jh-block Apr 15, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This specific issue is invalid, though it does reveal another issue. RFC 8252 Section 7.3 says that for URLs pointing at loopback IP literals, any port can be used at the time of the request. However, we're using localhost and not an IP literal. Fixed.

RFC 8252 Section 7.3 specifies that dynamic port allowance applies to
loopback IP literals (127.0.0.1, [::1]), not "localhost". Switch the
redirect URI from localhost to 127.0.0.1, and whitelist both IPv4 and
IPv6 loopback addresses in the CIMD document.

Existing DCR-registered credentials using localhost will be treated as
stale and re-registered on next auth.
Copy link
Copy Markdown

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: d396ce9a2d

ℹ️ About Codex in GitHub

Codex has been enabled to automatically review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

When you sign up for Codex through ChatGPT, Codex can also answer questions or update the PR, like "@codex address that feedback".

Comment thread documentation/static/oauth/client-metadata.json Outdated
Comment thread documentation/static/oauth/client-metadata.json Outdated
Remove the "scope" field — goose passes an empty scope list and lets
the server advertise required scopes. Hardcoding "openid profile email"
would cause invalid_scope errors on MCP servers with different scope
requirements.

Add "refresh_token" to grant_types since goose attempts token refresh
on startup via stored credentials.
Copy link
Copy Markdown

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: ff7d059e5f

ℹ️ About Codex in GitHub

Codex has been enabled to automatically review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

When you sign up for Codex through ChatGPT, Codex can also answer questions or update the PR, like "@codex address that feedback".

Comment on lines +85 to +89
.start_authorization_with_metadata_url(
&[],
redirect_uri.as_str(),
Some("goose"),
Some(CLIENT_METADATA_URL),
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P1 Badge Preserve DCR fallback when CIMD URL cannot be fetched

Passing Some(CLIENT_METADATA_URL) unconditionally forces rmcp down the URL-based client-id path whenever the server advertises client_id_metadata_document_supported; in AuthorizationSession::new, that branch does not fall back to register_client if the authorization server later fails to resolve the metadata URL. In environments where the server has restricted egress (common for private/enterprise MCP deployments), OAuth now fails even though dynamic client registration would have worked before this change.

Useful? React with 👍 / 👎.

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

A server which cannot fetch CIMD documents but nonetheless advertises support for CIMD is misconfigured; it's not the client's responsibility to work around that.

let mut oauth_state = OAuthState::new(mcp_server_url, None).await?;

let redirect_uri = format!("http://localhost:{}/oauth_callback", used_addr.port());
let redirect_uri = format!("http://127.0.0.1:{}/oauth_callback", used_addr.port());
Copy link
Copy Markdown
Collaborator Author

@jh-block jh-block Apr 15, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This change is because we use a dynamic port. RFC 8252 Section 7.3 says that a redirect URL listed in a CIMD which points at a loopback IP literal matches the same URL with any port, but this behaviour is explicitly only for loopback IP literals, not for localhost.

@jh-block jh-block added this pull request to the merge queue Apr 15, 2026
Merged via the queue into main with commit 78b5b52 Apr 15, 2026
22 checks passed
@jh-block jh-block deleted the jhugo/issue-7071 branch April 15, 2026 16:14
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