पहुँच नियंत्रण

adk-auth का उपयोग करके AI agents के लिए एंटरप्राइज़-स्तरीय पहुँच नियंत्रण।

अवलोकन

adk-auth भूमिका-आधारित पहुँच नियंत्रण (RBAC), स्कोप-आधारित प्राधिकरण, ऑडिट लॉगिंग और SSO समर्थन को ADK agents के लिए प्रदान करता है। यह इस बात पर सुरक्षित, सूक्ष्म-स्तरीय नियंत्रण सक्षम करता है कि कौन से उपयोगकर्ता किन tools तक पहुँच सकते हैं।

आर्किटेक्चर

┌─────────────────────────────────────────────────────────────────┐
│                        Agent Request                             │
└─────────────────────────────────────────────────────────────────┘
                                │
                                ▼
┌─────────────────────────────────────────────────────────────────┐
│                     SSO Token Validation                         │
│  ┌─────────────┐  ┌─────────────┐  ┌─────────────────────────┐  │
│  │ Google      │  │ Azure AD    │  │ OIDC Discovery          │  │
│  │ Provider    │  │ Provider    │  │ (Okta, Auth0, etc)     │  │
│  └─────────────┘  └─────────────┘  └─────────────────────────┘  │
│                          │                                       │
│                   ┌──────┴──────┐                                │
│                   │ JWKS Cache  │  ← Auto-refresh keys          │
│                   └─────────────┘                                │
└─────────────────────────────────────────────────────────────────┘
                                │
                                ▼ TokenClaims
┌─────────────────────────────────────────────────────────────────┐
│                       Claims Mapper                              │
│                                                                  │
│    IdP Groups          →        adk-auth Roles                  │
│    ─────────────────────────────────────────                    │
│    "AdminGroup"        →        "admin"                         │
│    "DataAnalysts"      →        "analyst"                       │
│    (default)           →        "viewer"                        │
└─────────────────────────────────────────────────────────────────┘
                                │
                                ▼ Roles
┌─────────────────────────────────────────────────────────────────┐
│                      Access Control                              │
│                                                                  │
│    Role: admin                                                   │
│    ├── allow: AllTools                                          │
│    └── allow: AllAgents                                         │
│                                                                  │
│    Role: analyst                                                 │
│    ├── allow: Tool("search")                                    │
│    ├── allow: Tool("summarize")                                 │
│    └── deny:  Tool("code_exec")  ← Deny takes precedence        │
└─────────────────────────────────────────────────────────────────┘
                                │
                                ▼ Check Result
┌─────────────────────────────────────────────────────────────────┐
│                      Audit Logging                               │
│                                                                  │
│    {"user":"alice","resource":"search","outcome":"allowed"}     │
│    {"user":"bob","resource":"exec","outcome":"denied"}          │
└─────────────────────────────────────────────────────────────────┘
                                │
                                ▼
┌─────────────────────────────────────────────────────────────────┐
│                     Tool Execution                               │
│               (only if access granted)                          │
└─────────────────────────────────────────────────────────────────┘

डिज़ाइन सिद्धांत

1. अस्वीकृति की प्राथमिकता

जब किसी भूमिका में अनुमति और अस्वीकृति, दोनों नियम हों, तो अस्वीकृति हमेशा प्रभावी होती है:

let role = Role::new("limited")
    .allow(Permission::AllTools)      // Allow everything...
    .deny(Permission::Tool("admin")); // ...except admin

// Result: Can access any tool EXCEPT "admin"

2. बहु-भूमिका संयोजन

एकाधिक भूमिकाओं वाले उपयोगकर्ताओं को अनुमतियों का संघ प्राप्त होता है, लेकिन किसी भी भूमिका के अस्वीकृति नियम अब भी लागू होते हैं:

let ac = AccessControl::builder()
    .role(reader)    // allow: search
    .role(writer)    // allow: write
    .assign("alice", "reader")
    .assign("alice", "writer")
    .build()?;

// Alice can access both "search" AND "write"

3. स्पष्टता, अंतर्निहितता पर प्राथमिक

अनुमतियाँ स्पष्ट होती हैं - डिफ़ॉल्ट रूप से कोई पहुँच प्रदान नहीं की जाती:

let role = Role::new("empty");
// This role grants NO permissions

ac.check("user", &Permission::Tool("anything")); // → Denied

4. प्रमाणीकरण और प्राधिकरण का पृथक्करण

  • प्रमाणीकरण (SSO): यह सत्यापित करता है कि उपयोगकर्ता कौन है (JWT के माध्यम से)
  • प्राधिकरण (RBAC): यह निर्धारित करता है कि वे किस तक पहुँच सकते हैं
// Authentication: validate JWT, extract claims
let claims = provider.validate(token).await?;

// Authorization: check specific permission
ac.check(&claims.sub, &Permission::Tool("search"))?;

// Combined: SsoAccessControl does both
sso.check_token(token, &permission).await?;

इंस्टॉलेशन

[dependencies]
adk-auth = "2.1.0"

# For SSO/OAuth support
adk-auth = { version = "2.1.0", features = ["sso"] }

मुख्य घटक

अनुमति

pub enum Permission {
    Tool(String),     // Specific tool by name
    AllTools,         // Wildcard: all tools
    Agent(String),    // Specific agent by name  
    AllAgents,        // Wildcard: all agents
}

भूमिका

let analyst = Role::new("analyst")
    .allow(Permission::Tool("search".into()))
    .allow(Permission::Tool("summarize".into()))
    .deny(Permission::Tool("code_exec".into()));

AccessControl

let ac = AccessControl::builder()
    .role(admin)
    .role(analyst)
    .assign("alice@company.com", "admin")
    .assign("bob@company.com", "analyst")
    .build()?;

// Check permission
ac.check("bob@company.com", &Permission::Tool("search".into()))?;

ProtectedTool

स्वचालित अनुमति जाँच के साथ किसी tool को रैप करता है:

use adk_auth::ToolExt;

let protected = my_tool.with_access_control(Arc::new(ac));

// When executed, checks permission before running
protected.execute(ctx, args).await?;

AuthMiddleware

कई tools को एक साथ सुरक्षित करें:

let middleware = AuthMiddleware::new(ac);
let protected_tools = middleware.protect_all(tools);

ScopeGuard

JWT claims या session state से प्राप्त request-स्तरीय प्राधिकरण के लिए scopes का उपयोग करें:

use adk_auth::{ContextScopeResolver, ScopeGuard};

let guard = ScopeGuard::new(ContextScopeResolver);
let protected = guard.protect(my_tool);

RBAC + scopes का संयोजन

RBAC इस प्रश्न का उत्तर देता है, "क्या यह उपयोगकर्ता tool तक पहुँच सकता है?" Scopes इस प्रश्न का उत्तर देते हैं, "क्या यह विशिष्ट request अभी अधिकृत है?"

use std::sync::Arc;
use adk_auth::{AuthMiddleware, ContextScopeResolver, ScopeGuard};

let rbac = AuthMiddleware::new(ac);
let scoped = ScopeGuard::new(ContextScopeResolver);

let protected = scoped.protect(rbac.protect(transfer_tool));

SSO एकीकरण

समर्थित प्रदाता

प्रदातानिर्माताजारीकर्ता
GoogleGoogleProvider::new(client_id)accounts.google.com
Azure ADAzureADProvider::new(tenant, client) या AzureADProvider::multi_tenant(client).with_allowed_tenants(["tenant-id"])login.microsoftonline.com
OktaOktaProvider::new(domain, client){domain}/oauth2/default
Auth0Auth0Provider::new(domain, audience){domain}/
GenericOidcProvider::from_discovery(issuer, client)कोई भी OIDC प्रदाता

AzureADProvider::multi_tenant() कॉन्फ़िगर किए गए ऑडियंस के लिए किसी भी टेनेंट को स्वीकार करता है, जब तक कि आप इसे with_allowed_tenants(...) के साथ स्पष्ट रूप से प्रतिबंधित न करें।

TokenClaims

मान्य JWTs से निकाले गए दावे:

pub struct TokenClaims {
    pub sub: String,              // Subject (user ID)
    pub email: Option<String>,    // Email
    pub name: Option<String>,     // Display name
    pub groups: Vec<String>,      // IdP groups
    pub roles: Vec<String>,       // IdP roles
    pub hd: Option<String>,       // Google hosted domain
    pub tid: Option<String>,      // Azure tenant ID
    // ... more standard OIDC claims
}

ClaimsMapper

IdP समूहों को adk-auth भूमिकाओं से मैप करता है:

let mapper = ClaimsMapper::builder()
    .map_group("AdminGroup", "admin")
    .map_group("Users", "viewer")
    .default_role("guest")
    .user_id_from_email()
    .build();

user_id_from_email() केवल तभी ईमेल दावे का उपयोग करता है जब email_verified == true; अन्यथा यह sub पर वापस आ जाता है।

SsoAccessControl

SSO सत्यापन को RBAC के साथ एक ही कॉल में संयोजित करता है:

let sso = SsoAccessControl::builder()
    .validator(GoogleProvider::new("client-id"))
    .mapper(mapper)
    .access_control(ac)
    .audit_sink(audit)
    .build()?;

// Validate token + check permission + audit log
let claims = sso.check_token(token, &Permission::Tool("search".into())).await?;

ऑडिट लॉगिंग

FileAuditSink

let audit = FileAuditSink::new("/var/log/adk/audit.jsonl")?;
let middleware = AuthMiddleware::with_audit(ac, audit);

आउटपुट फ़ॉर्मेट (JSONL)

{"timestamp":"2025-01-01T10:30:00Z","user":"bob","session_id":"sess-123","event_type":"tool_access","resource":"search","outcome":"allowed"}
{"timestamp":"2025-01-01T10:30:01Z","user":"bob","session_id":"sess-123","event_type":"tool_access","resource":"code_exec","outcome":"denied"}

कस्टम ऑडिट सिंक

use adk_auth::{AuditSink, AuditEvent, AuthError};
use async_trait::async_trait;

pub struct DatabaseAuditSink { /* ... */ }

#[async_trait]
impl AuditSink for DatabaseAuditSink {
    async fn log(&self, event: AuditEvent) -> Result<(), AuthError> {
        // Insert into database
        sqlx::query("INSERT INTO audit_log ...")
            .bind(event.user)
            .bind(event.resource)
            .execute(&self.pool)
            .await?;
        Ok(())
    }
}

उदाहरण

cargo check -p adk-auth
cargo check -p adk-auth --features sso

सुरक्षा की सर्वोत्तम प्रक्रियाएँ

अभ्यासविवरण
डिफ़ॉल्ट रूप से अस्वीकार करेंकेवल स्पष्ट रूप से आवश्यक अनुमतियाँ प्रदान करें
स्पष्ट अस्वीकृतियाँखतरनाक कार्रवाइयों के लिए अस्वीकृति नियम जोड़ें
हर चीज़ का ऑडिट करेंअनुपालन के लिए लॉगिंग सक्षम करें
सर्वर-साइड पर सत्यापित करेंसर्वर पर हमेशा JWTs को सत्यापित करें
HTTPS का उपयोग करेंJWKS एंडपॉइंट के लिए सुरक्षित कनेक्शन आवश्यक हैं
कुंजियाँ रोटेट करेंJWKS कैश हर घंटे स्वचालित रूप से रीफ़्रेश होता है
टोकन का जीवनकाल सीमित करेंअल्पकालिक एक्सेस टोकन का उपयोग करें
Azure टेनेंट प्रतिबंधित करेंमल्टी-टेनेंट Azure ऐप्स के लिए, with_allowed_tenants(...) कॉन्फ़िगर करें
पहचान मैपिंग से पहले ईमेल सत्यापित करेंईमेल असत्यापित होने पर user_id_from_email() अब sub पर वापस आ जाता है
निरस्तीकरण की योजना बनाएँटोकन निरस्तीकरण अंतर्निहित नहीं है; यदि आपको तुरंत पहुँच रोकने की आवश्यकता है, तो इसे कस्टम वैलिडेटर में लागू करें
महँगे स्कोप लुकअप को कैश करेंयदि आपका ScopeResolver बाहरी सिस्टम को कॉल करता है, तो प्रति अनुरोध/सत्र परिणाम को कैश करें

प्रमाणीकरण ब्रिज

जब आप चाहते हैं कि adk-auth, adk-server के लिए पुन: उपयोग योग्य JWT-आधारित अनुरोध एक्सट्रैक्टर प्रदान करे, तब auth-bridge सक्षम करें:

use adk_auth::auth_bridge::JwtRequestContextExtractor;
use adk_auth::sso::{ClaimsMapper, GoogleProvider};

let extractor = JwtRequestContextExtractor::builder()
    .validator(GoogleProvider::new("client-id"))
    .mapper(ClaimsMapper::builder().user_id_from_email().build())
    .build()?;

एक्सट्रैक्टर Bearer टोकन को मान्य करता है, user_id को ClaimsMapper के साथ मैप करता है, और JWT scope / scp क्लेम्स को RequestContext.scopes में अग्रेषित करता है।

सीक्रेट प्रदाता

टूल्स ToolContext::get_secret और InvocationContext::get_secret के माध्यम से रनटाइम सीक्रेट्स तक पहुँचते हैं। इनके पीछे adk_auth::secrets::SecretProvider है, जिसके क्लाउड कार्यान्वयन फीचर फ़्लैग्स के पीछे उपलब्ध हैं:

प्रदातासुविधा
AWS Secrets Manageraws-secrets
Azure Key Vaultazure-keyvault
GCP Secret Managergcp-secrets

किसी रन से एक को इस रूप में लपेटकर संलग्न करें: SecretService

use adk_auth::secrets::{CachedSecretProvider, SecretProvider, SecretServiceAdapter};
use std::sync::Arc;
use std::time::Duration;

// Any SecretProvider — here wrapped in the cache
let cached = Arc::new(CachedSecretProvider::new(provider, Duration::from_secs(300)));
let service = Arc::new(SecretServiceAdapter::new(cached));

प्रति-टूल प्राधिकरण

डिफ़ॉल्ट रूप से, संदर्भ रखने वाला कोई भी टूल किसी भी सीक्रेट का नाम दे सकता है, और प्रदाता को केवल वही नाम दिखाई देता है — ऐसा कुछ भी अलग नहीं करता कि कोई मौसम टूल अपनी API कुंजी माँग रहा है या वही टूल भुगतान क्रेडेंशियल माँग रहा है। प्रदाता से संपर्क करने से पहले AuthorizingSecretService प्रत्येक टूल के लिए निर्णय लेता है:

use adk_auth::secrets::authorizing::{AuthorizingSecretService, SecretGrant};
use std::sync::Arc;

let service = Arc::new(
    AuthorizingSecretService::new(inner)
        .grant("weather_lookup", SecretGrant::none().name("weather-api-key"))
        .grant("charge_card", SecretGrant::none().prefix("billing/"))
        .with_audit_sink(audit_sink),
);
नियमव्यवहार
टूल के पास नाम को कवर करने वाली अनुमति हैअनुमति दी गई
टूल के पास ऐसी अनुमति है जो नाम को कवर नहीं करतीअस्वीकृत; प्रदाता को कभी कॉल नहीं किया जाता
उपकरण को कोई अनुमति नहींअस्वीकृत
अनुरोध में उपकरण की पहचान नहीं हैअस्वीकृत, जब तक grant_untooled इसे न खोले

जब तक अनुमति न दी जाए, तब तक सब कुछ अस्वीकृत रहता है, और अस्वीकृति Unauthorized त्रुटि लौटाती है। अस्वीकृत नाम को कभी खोजा नहीं जाता, इसलिए वह प्रदाता-पक्ष के एक्सेस लॉग में पढ़ने के प्रयास के रूप में दिखाई नहीं देता।

पहचान ऐसी चीज़ नहीं है जिसे कोई टूल स्वयं घोषित करता है। LlmAgent भेजे गए टूल का नाम अनुरोध पर ऐप, उपयोगकर्ता, सत्र और इनवोकेशन के साथ अंकित करता है, इसलिए कोई टूल किसी अन्य टूल की पहचान प्रस्तुत नहीं कर सकता। कोई टूल केवल एक उद्देश्य जोड़ सकता है:

// inside a tool
let key = ctx.get_secret_for_purpose("weather-api-key", "call the forecast endpoint").await?;

नोट: टूल के रूप में इनवोक किया गया एजेंट एक ToolContext को पार करता है, जिसकी अपनी कोई पहचान नहीं होती, इसलिए उस एजेंट के भीतर किए गए एक्सेस आंतरिक टूल की पहचान के बजाय बाहरी एजेंट की पहचान प्रस्तुत करते हैं। उसी के अनुसार अनुमति दें।

एक्सेस का ऑडिट

SecretAuditSink प्रत्येक निर्णय के लिए एक SecretAccessDecision प्राप्त करता है, जिसमें परिणाम, सीक्रेट का नाम, टूल, उपयोगकर्ता, इनवोकेशन और कारण शामिल होते हैं — लेकिन कभी भी सीक्रेट का मान नहीं। अनुमतियाँ भी info पर और अस्वीकृतियाँ warn पर लॉग की जाती हैं।

कैशिंग

CachedSecretProvider अपने TTL के लिए एक मान प्रदान करता है, फिर उसे दोबारा प्राप्त करता है। यह सीमित और रद्द करने योग्य है:

नियंत्रणव्यवहार
with_max_entries(n)अधिकतम n नाम कैश किए जाते हैं; पूरा होने पर सबसे कम हाल में उपयोग किया गया नाम हटा दिया जाता है। डिफ़ॉल्ट 128 है; 0 कैशिंग अक्षम करता है
invalidate(name)एक गुप्त मान तुरंत हटा देता है — किसी गुप्त मान के बदलने पर इसका उपयोग करें, ताकि उसके TTL के शेष समय के दौरान पुराना मान उपलब्ध न कराया जाए
invalidate_all()सब कुछ हटा देता है
purge_expired()समाप्त हो चुकी प्रविष्टियों को दोबारा पढ़े जाने की प्रतीक्षा किए बिना हटा देता है

जब गुप्त नाम इनपुट से व्युत्पन्न किए जाते हैं, तब एक बाउंड महत्वपूर्ण होता है: इसके बिना कैश प्रक्रिया के पूरे जीवनकाल तक बढ़ सकता है।

कैश क्या करता है और क्या सुनिश्चित नहीं करता

एक TTL यह नियंत्रित करता है कि कैश क्या लौटाता है, न कि कोई मान प्रक्रिया की मेमोरी में कितनी देर तक रहता है। प्रविष्टियाँ समाप्त होने, बाहर निकाले जाने या अमान्य किए जाने पर शून्यीकृत कर दी जाती हैं, जिससे उनका निवास-समय लगभग TTL तक सीमित हो जाता है। यह कमी है, मिटाना नहीं — एक String को पहले ही पुनः आवंटित किया जा चुका हो सकता है, एलोकेटर द्वारा कॉपी किया गया हो सकता है, डिस्क पर स्वैप किया गया हो सकता है, या कोर डंप में कैप्चर किया गया हो सकता है। कैश के लिए डिबग आउटपुट को संवेदनशील जानकारी हटाकर दिखाया जाता है, ताकि डायग्नोस्टिक प्रिंट किसी मान को लीक न कर सके।

महत्वपूर्ण: एक साधारण SecretProvider अपनी कोई नीति लागू नहीं करता — संदर्भ रखने वाला कोई भी टूल उन सभी नामों का अनुरोध कर सकता है जिन्हें आधारभूत क्रेडेंशियल पढ़ सकते हैं। प्रति-टूल सीमा प्राप्त करने के लिए इसे AuthorizingSecretService में रैप करें, और क्लाउड क्रेडेंशियल को भी सीमित दायरे में रखें: प्रत्येक डिप्लॉयमेंट के लिए एक IAM पहचान, जिसे केवल उन सीक्रेट्स तक पहुँच हो जिनकी उस डिप्लॉयमेंट को आवश्यकता है। महत्वपूर्ण: प्रोवाइडर इंटरफ़ेस केवल सीक्रेट नाम लेता है। ADK स्तर पर प्रति-टूल अनुमति, नेमस्पेस या एक्सेस ऑडिट नहीं है, इसलिए संदर्भ रखने वाला कोई भी टूल उन सभी नामों का अनुरोध कर सकता है जिन्हें आधारभूत क्रेडेंशियल पढ़ सकते हैं। क्लाउड क्रेडेंशियल को स्वयं सीमित दायरे में रखें — प्रत्येक डिप्लॉयमेंट के लिए एक IAM पहचान, जिसे केवल उन सीक्रेट्स तक पहुँच हो जिनकी उस डिप्लॉयमेंट को आवश्यकता है — और प्रोवाइडर-पक्ष के ऑडिट लॉग को एक्सेस के रिकॉर्ड के रूप में मानें।

एक्सट्रैक्टर किससे सुरक्षा करता है

एक्सट्रैक्टर कॉन्फ़िगर करने से प्रत्येक गैर-सार्वजनिक रूट के लिए प्रमाणीकरण चालू हो जाता है:

मार्गकॉन्फ़िगर किए गए एक्सट्रैक्टर के साथ व्यवहार
/api/sessions/*, /api/apps/*, आर्टिफैक्ट, डीबगमान्य टोकन के बिना 401
/api/ui/* — ब्रिज, सूचनाएँ, संसाधनमान्य टोकन के बिना 401; प्रमाणित उपयोगकर्ता अनुरोध के मुख्य भाग में नामित किसी भी उपयोगकर्ता का स्थान लेता है
/api/run*वैध टोकन के बिना 401; प्रमाणित उपयोगकर्ता दिए गए उपयोगकर्ता को अधिलेखित करता है
/healthसार्वजनिक

UI ब्रिज स्थिति अनुरोध के बॉडी से लिए गए (app_name, user_id, session_id) पर आधारित होती है, इसलिए प्रमाणीकृत उपयोगकर्ता को बॉडी के मान के स्थान पर प्रतिस्थापित किया जाता है, उस पर भरोसा नहीं किया जाता। पंजीकृत UI संसाधन उसे पंजीकृत करने वाले उपयोगकर्ता को रिकॉर्ड करता है; केवल वही उपयोगकर्ता उसे पढ़ या प्रतिस्थापित कर सकता है, और किसी अन्य उपयोगकर्ता के संसाधन को पढ़ने पर 404 उत्तर मिलता है, ताकि URI का अस्तित्व प्रकट न हो।

कोई भी एक्सट्रैक्टर कॉन्फ़िगर न होने पर बाँधने के लिए कोई प्रमाणीकृत पहचान उपलब्ध नहीं होती, इसलिए रूट खुले रहते हैं और संसाधन वैश्विक रूप से दृश्यमान रहते हैं। प्रमाणीकरण वैकल्पिक है — ऐसे किसी भी परिनियोजन के लिए एक्सट्रैक्टर कॉन्फ़िगर करें जो एकल विश्वसनीय उपयोगकर्ता का न हो।

त्रुटि प्रबंधन

use adk_auth::{AccessDenied, AuthError};
use adk_auth::sso::TokenError;

// RBAC errors
match ac.check("user", &Permission::Tool("admin".into())) {
    Ok(()) => { /* access granted */ }
    Err(AccessDenied { user, permission }) => {
        eprintln!("Denied: {} cannot access {}", user, permission);
    }
}

// SSO errors
match provider.validate(token).await {
    Ok(claims) => { /* token valid */ }
    Err(TokenError::Expired) => { /* token expired */ }
    Err(TokenError::InvalidSignature) => { /* signature invalid */ }
    Err(TokenError::InvalidIssuer { expected, actual }) => { /* wrong issuer */ }
    Err(e) => { /* other error */ }
}

पिछला: ← मूल्यांकन | अगला: टूल प्राधिकरण →

A2A एंडपॉइंट્સ

मार्गप्रमाणीकरण
GET /.well-known/agent.jsonसार्वजनिक — सहकर्मी क्रेडेंशियल रखने से पहले कार्ड प्राप्त करते हैं
POST /a2aआवश्यक, जब कोई RequestContextExtractor कॉन्फ़िगर किया गया हो
POST /a2a/streamआवश्यक, जब RequestContextExtractor कॉन्फ़िगर किया गया हो

JSON-RPC रूट एजेंट और टूल का कार्य निष्पादित करते हैं, इसलिए वे सेशन, आर्टिफैक्ट और डीबग राउटर के समान लेयर रखते हैं। कॉन्फ़िगर किया गया कोई एक्सट्रैक्टर न होने पर मांगने के लिए कोई क्रेडेंशियल नहीं होता और रूट खुले रहते हैं, इसलिए गेट जोड़ने से मौजूदा डिप्लॉयमेंट बाधित नहीं होता।

महत्वपूर्ण: ये रूट पहले राउटर रूट पर, /api पर लागू लेयर के बाहर, मर्ज किए गए थे। ऐसा डिप्लॉयमेंट जो हर दूसरे म्यूटेशन सरफ़ेस को प्रमाणित करता था, फिर भी उस पोर्ट तक पहुँच रखने वाले किसी भी क्लाइंट को एजेंट चलाने और उसकी लागत वहन करने देता था। यह create_app_with_a2a और ServerBuilder::build दोनों पर लागू था।

A2aServer::builder() डिफ़ॉल्ट रूप से 127.0.0.1:8080 से बाइंड होता है। इसे एक्सपोज़ करने के लिए bind_addr कॉल करें और ऐसा करने से पहले एक एक्सट्रैक्टर कॉन्फ़िगर करें। जनरेट किया गया a2a-server स्कैफ़ोल्ड भी इसी नियम का पालन करता है और व्यापक बाइंड का विकल्प चुनने के लिए BIND_HOST पढ़ता है।