agentd/auth/mod.rs
1// SPDX-License-Identifier: AGPL-3.0-only
2//! Endpoint authentication — the interactive and workload credential providers
3//! and the token cache they share.
4//!
5//! Static headers (`mcp::auth`) and the AAuth request-signer (`aauth`) supply
6//! the `static` and `aauth` providers. This module owns the rest: the
7//! [`Kind::Cred`](crate::state::Kind::Cred)-backed [`cache`], the OAuth 2.1 /
8//! OIDC [`oauth2`] flows (device grant, browser + PKCE, refresh, discovery)
9//! behind `agentd login`, and the AWS SigV4 / IAM Identity Center providers.
10//! Everything but the cache is gated on the `oauth` cargo feature, so a build
11//! without it carries no interactive-login code at all.
12
13pub mod cache;
14
15#[cfg(feature = "oauth")]
16pub mod oauth2;
17
18#[cfg(feature = "oauth")]
19pub mod challenge;
20
21#[cfg(feature = "oauth")]
22pub mod login;
23
24#[cfg(feature = "oauth")]
25pub mod device;
26
27#[cfg(feature = "oauth")]
28pub mod aws;
29
30#[cfg(feature = "oauth")]
31pub mod aws_sso;
32
33#[cfg(feature = "oauth")]
34pub mod browser;
35
36/// Canonicalize a login/logout target: `mcp:<name>` on a server that references
37/// a service-catalog entry becomes `service:<entry>`, the key the daemon's
38/// connect path actually reads. Every server pointing at that entry shares one
39/// credential, so a login must land where all of them look and a logout must
40/// revoke it for all of them at once. Deliberately outside the `oauth` feature
41/// gate, so logout still resolves in a build without interactive login.
42pub fn canonical_target(settings: &crate::config::v2::Settings, target: &str) -> String {
43 if let Some(name) = target.strip_prefix("mcp:")
44 && let Some(svc) = settings
45 .mcp
46 .servers
47 .iter()
48 .find(|s| s.name == name)
49 .and_then(|s| s.service.clone())
50 {
51 return format!("service:{svc}");
52 }
53 target.to_string()
54}