Files
codex/codex-rs/rmcp-client/src/oauth_callback_tests.rs
stevenlee-oai 9be8d6e1c3 Harden MCP OAuth callback handling (#40691)
## Why

MCP servers can share an OAuth callback URL. Without a validated issuer or a
server-specific callback path, an authorization response could be associated
with the wrong server.

## What changed

- Use stable callbacks when authorization metadata advertises issuer-bound
  responses, and validate the returned issuer before exchanging the code.
- Retain server-specific callback IDs for providers without issuer support,
  including fallback to the global or default callback for legacy registered
  clients.
- Persist registered callback URLs for MCP servers and plugins, and insert the
  active listener port into portless loopback redirects.

## Testing

Add coverage for issuer validation, callback-mode discovery, registered and
legacy clients, plugin OAuth, CLI persistence, and loopback listener ports.

GitOrigin-RevId: 2878c92e237fc17fd3def0bd2e1cce3e104a3db8
2026-08-25 20:26:23 +00:00

64 lines
1.8 KiB
Rust

use pretty_assertions::assert_eq;
use super::McpOAuthCallbackMode;
use super::callback_id_from_server_url;
use super::resolve_mcp_oauth_callback_url;
use super::validate_callback_redirect;
#[test]
fn resolved_callbacks_follow_the_selected_mix_up_defense() {
let server_url = "https://mcp.example.com/mcp?tenant=one";
let callback_id = callback_id_from_server_url(server_url).expect("resolve callback ID");
let distinct_callback = format!("http://127.0.0.1/callback/{callback_id}");
for (callback, mode, expected) in [
(
None,
McpOAuthCallbackMode::CallbackSpecific,
distinct_callback.as_str(),
),
(
None,
McpOAuthCallbackMode::IssuerBound,
"http://127.0.0.1/callback",
),
(
Some("http://127.0.0.1:8080/oauth/callback"),
McpOAuthCallbackMode::IssuerBound,
"http://127.0.0.1:8080/oauth/callback",
),
] {
assert_eq!(
resolve_mcp_oauth_callback_url(server_url, callback, mode)
.expect("resolve registered callback"),
expected
);
}
}
#[test]
fn callback_redirect_requires_a_server_specific_id_or_issuer_support() {
for (redirect_uri, mode, expected_valid) in [
(
"http://127.0.0.1/callback/expected-id",
McpOAuthCallbackMode::CallbackSpecific,
true,
),
(
"http://127.0.0.1/callback",
McpOAuthCallbackMode::IssuerBound,
true,
),
(
"http://127.0.0.1/callback/wrong-id",
McpOAuthCallbackMode::CallbackSpecific,
false,
),
] {
assert_eq!(
validate_callback_redirect(redirect_uri, "expected-id", mode).is_ok(),
expected_valid
);
}
}