Files
codex/codex-rs/rmcp-client/Cargo.toml
T
Nick Steele ecc78e4cf5 Add renewable EMA HTTP authentication and credential versioning (#49987)
## What changed

- Add `EmaAuthenticatedHttpClient` to cache and renew resource bearers, serialize concurrent renewals, and include authentication time in the request deadline. Confine bearers to the configured MCP endpoint and reject redirects.
- Return authentication-required errors for `401` responses without replaying MCP operations. Preserve a newer cached bearer when a delayed response rejects an older one.
- Add revocable request authority that cancels pending requests and ends response streams.
- Pin enterprise credentials to a persistent version advanced on save or deletion. Use short credential locks and invalidate rejected grants only when their record and version are still current, preserving newer logins.
- Hide keyring account identifiers from enterprise credential errors and traces while preserving authentication failure classification.

## Testing

Add tests for token expiry and renewal, endpoint confinement, redirects, request deadlines, revocation during renewal and streaming, delayed `401` responses, credential replacement and logout races, and credential error privacy.

GitOrigin-RevId: ee3e5cf7ecbba3d09e1ab29ed4fbb2a35eacc60d
2026-10-01 13:57:48 +00:00

109 lines
3.3 KiB
TOML

[package]
name = "codex-rmcp-client"
version.workspace = true
edition.workspace = true
license.workspace = true
[lints]
workspace = true
[dependencies]
anyhow = "1"
axum = { workspace = true, default-features = false, features = [
"http1",
"json",
"tokio",
] }
base64 = { workspace = true }
codex-api = { workspace = true }
codex-config = { workspace = true }
codex-exec-server = { workspace = true }
codex-http-client = { workspace = true }
codex-keyring-store = { workspace = true }
codex-network-proxy = { workspace = true }
codex-otel = { workspace = true }
codex-protocol = { workspace = true }
codex-secrets = { workspace = true }
codex-utils-path-uri = { workspace = true }
codex-utils-pty = { workspace = true }
codex-utils-home-dir = { workspace = true }
bytes = { workspace = true }
futures = { workspace = true, default-features = false, features = ["std"] }
http = { workspace = true }
keyring = { workspace = true, features = ["crypto-rust"] }
memchr = { workspace = true }
oauth2 = "5"
rmcp = { workspace = true, default-features = false, features = [
"auth-enterprise-managed",
"base64",
"client",
"macros",
"schemars",
"server",
"transport-async-rw",
"transport-child-process",
"transport-streamable-http-client",
"transport-streamable-http-server",
] }
serde = { workspace = true, features = ["derive"] }
serde_json = { workspace = true }
sha2 = { workspace = true }
sse-stream = "0.2.5"
tempfile = { workspace = true }
thiserror = { workspace = true }
tiny_http = { workspace = true }
tokio = { workspace = true, features = [
"io-util",
"macros",
"process",
"signal",
"rt-multi-thread",
"sync",
"io-std",
"time",
] }
tokio-util = { workspace = true, features = ["rt"] }
tracing = { workspace = true, features = ["log"] }
url = { workspace = true }
urlencoding = { workspace = true }
webbrowser = { workspace = true }
which = { workspace = true }
[dev-dependencies]
opentelemetry_sdk = { workspace = true, features = ["testing"] }
codex-http-client = { workspace = true }
codex-utils-cargo-bin = { workspace = true }
pretty_assertions = { workspace = true }
serial_test = { workspace = true }
tracing-subscriber = { workspace = true }
tracing-test = { workspace = true, features = ["no-env-filter"] }
wiremock = { workspace = true }
[target.'cfg(unix)'.dependencies]
libc = { workspace = true }
[target.'cfg(target_os = "linux")'.dependencies]
keyring = { workspace = true, features = ["linux-native-async-persistent"] }
[target.'cfg(target_os = "macos")'.dependencies]
keyring = { workspace = true, features = ["apple-native"] }
[target.'cfg(target_os = "windows")'.dependencies]
keyring = { workspace = true, features = ["windows-native"] }
windows-sys = { version = "0.52", features = ["Win32_Storage_FileSystem"] }
[target.'cfg(any(target_os = "freebsd", target_os = "openbsd"))'.dependencies]
keyring = { workspace = true, features = ["sync-secret-service"] }
# These tests are compiled through `#[path]` inside the inline `oauth::tests` module. Cargo-shear
# cannot resolve those nested module paths and otherwise reports the linked files as unlinked.
[package.metadata.cargo-shear]
ignored-paths = [
"src/oauth/tests/persistor_tests.rs",
"src/oauth/tests/credential_store_tests.rs",
"src/oauth/tests/telemetry_tests.rs",
]
[lib]
doctest = false