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}