Skip to main content

agent_framework_azure/
credential.rs

1//! Token credential abstraction for Microsoft Entra ID (Azure AD) bearer-token
2//! authentication.
3
4use agent_framework_core::error::Result;
5use async_trait::async_trait;
6
7/// Supplies bearer tokens for Microsoft Entra ID authentication.
8///
9/// Implement this to integrate a real credential chain (e.g. the
10/// [`AzureCliCredential`](crate::AzureCliCredential),
11/// [`ClientSecretCredential`](crate::ClientSecretCredential),
12/// [`ManagedIdentityCredential`](crate::ManagedIdentityCredential), and
13/// [`ChainedTokenCredential`](crate::ChainedTokenCredential) that ship with
14/// this crate); [`StaticTokenCredential`] is provided for a fixed/pre-fetched
15/// token (useful in tests, short-lived scripts, or when the caller manages
16/// token refresh externally).
17///
18/// Most credentials are bound to a single configured *scope* (audience) and
19/// [`get_token`](Self::get_token) fetches a token for it. A caller that needs a
20/// token for a *different* scope from the same credential uses
21/// [`get_token_for_scope`](Self::get_token_for_scope); the default
22/// implementation ignores the scope and delegates to
23/// [`get_token`](Self::get_token), which is correct for fixed-token credentials
24/// but is overridden by the real credentials so each scope is fetched (and
25/// cached) independently.
26#[async_trait]
27pub trait TokenCredential: Send + Sync {
28    /// Fetch a bearer token to send as `Authorization: Bearer <token>`.
29    async fn get_token(&self) -> Result<String>;
30
31    /// Fetch a bearer token for a specific `scope` (audience), e.g.
32    /// `"https://ai.azure.com/.default"`.
33    ///
34    /// The default implementation ignores `scope` and delegates to
35    /// [`get_token`](Self::get_token) — appropriate for credentials that wrap a
36    /// single fixed token. Credentials that mint tokens per audience override
37    /// this to honor the requested scope.
38    async fn get_token_for_scope(&self, _scope: &str) -> Result<String> {
39        self.get_token().await
40    }
41}
42
43/// A [`TokenCredential`] that always returns the same, pre-fetched token.
44#[derive(Debug, Clone)]
45pub struct StaticTokenCredential {
46    token: String,
47}
48
49impl StaticTokenCredential {
50    /// Wrap a fixed bearer token.
51    pub fn new(token: impl Into<String>) -> Self {
52        Self {
53            token: token.into(),
54        }
55    }
56}
57
58#[async_trait]
59impl TokenCredential for StaticTokenCredential {
60    async fn get_token(&self) -> Result<String> {
61        Ok(self.token.clone())
62    }
63}
64
65#[cfg(test)]
66mod tests {
67    use super::*;
68
69    #[tokio::test]
70    async fn static_token_credential_returns_configured_token() {
71        let cred = StaticTokenCredential::new("my-token");
72        assert_eq!(cred.get_token().await.unwrap(), "my-token");
73    }
74}