adk-auth
Access control and authentication for Rust Agent Development Kit (ADK-Rust).
Overview
adk-auth provides enterprise-grade access control for AI agents:
- Declarative scope-based security — tools declare required scopes, framework enforces automatically
- Role-based access control — define roles with allow/deny permissions, deny takes precedence
- Audit logging — log all access attempts to JSONL files
- SSO/OAuth — JWT validation with Google, Azure AD, Okta, Auth0, and generic OIDC providers
- Auth bridge — flow authenticated identity from HTTP requests into agent execution via
adk-server
Installation
[]
= "0.5.0"
# With SSO/JWT validation
= { = "0.5.0", = ["sso"] }
# With auth bridge for adk-server identity flow (implies sso)
= { = "0.5.0", = ["auth-bridge"] }
Features
Core RBAC, scope-based security, and audit logging are always available with no feature flags.
| Feature | Description |
|---|---|
sso |
JWT/OIDC providers (Google, Azure AD, Okta, Auth0, generic OIDC) |
auth-bridge |
JwtRequestContextExtractor for adk-server identity flow (implies sso) |
Declarative Scope-Based Security
Tools declare what scopes they need. The framework enforces before execution — no imperative checks in your handlers:
use FunctionTool;
use ;
// Tool declares its required scopes
let transfer = new
.with_scopes;
// ScopeGuard enforces automatically
let guard = new;
let protected = guard.protect;
// Or wrap all tools at once
let protected_tools = guard.protect_all;
With audit logging:
let guard = with_audit;
let protected = guard.protect;
// All scope checks (allowed + denied) are logged
You can also use the extension trait for inline wrapping:
use ScopeToolExt;
let protected = my_tool.with_scope_guard;
Pluggable resolvers:
| Resolver | Source |
|---|---|
ContextScopeResolver |
Delegates to ToolContext::user_scopes() (JWT claims, session state) |
StaticScopeResolver |
Fixed scopes — useful for testing |
Custom impl ScopeResolver |
Any async source (database, external IdP, etc.) |
For resolvers that call external services, cache the resolved scopes at the request or session layer to avoid repeated lookups during multi-tool runs.
Role-Based Access Control
use ;
// Define roles
let admin = new.allow;
let user = new
.allow
.deny;
// Build access control
let ac = builder
.role
.role
.assign
.assign
.build?;
// Protect tools
let middleware = new;
let protected_tools = middleware.protect_all;
Deny always takes precedence over allow, regardless of role assignment order. If a user has both an editor role (allow all tools) and a restricted role (deny code_exec), code_exec is denied.
You can also use the extension trait:
use ToolExt;
let protected = my_tool.with_access_control;
Combining RBAC + Scopes
Use RBAC for coarse tool/agent entitlement and scopes for request-level constraints:
use Arc;
use ;
let rbac = new;
let scoped = new;
let protected = scoped.protect;
SSO Integration
Enable with features = ["sso"]:
use ;
// Create provider
let provider = new;
// Map IdP groups to roles
let mapper = builder
.map_group
.default_role
.user_id_from_email
.build;
// Combined SSO + RBAC
let sso = builder
.validator
.mapper
.access_control
.build?;
// Validate token and check permission
let claims = sso.check_token.await?;
println!;
User ID Claim Selection
The ClaimsMapper builder controls which JWT claim becomes the user_id:
| Method | Claim | Fallback |
|---|---|---|
user_id_from_sub() (default) |
sub |
— |
user_id_from_email() |
email (only when email_verified == true) |
sub |
user_id_from_preferred_username() |
preferred_username |
sub |
user_id_from_claim("custom") |
Any custom claim | sub |
Providers
| Provider | Usage |
|---|---|
GoogleProvider::new(client_id) |
|
| Azure AD | AzureADProvider::new(tenant_id, client_id) or ::multi_tenant(client_id).with_allowed_tenants(["tenant-id"]) |
| Okta | OktaProvider::new(domain, client_id) or ::with_auth_server(domain, server_id, client_id) |
| Auth0 | Auth0Provider::new(domain, audience) |
| Generic OIDC | OidcProvider::from_discovery(issuer, client_id).await or ::new(issuer, client_id, jwks_uri) |
| Custom JWT | JwtValidator::builder().issuer(iss).jwks_uri(uri).audience(aud).build()? |
AzureADProvider::multi_tenant() accepts tokens from any tenant targeting the configured audience unless you restrict it with with_allowed_tenants(...).
OidcProvider::from_discovery() rejects discovery documents whose issuer does not match the requested issuer URL.
All providers implement the TokenValidator trait — you can implement it for any custom identity provider.
Auth Bridge
Enable with features = ["auth-bridge"] to validate Bearer tokens directly into adk-server request contexts:
use JwtRequestContextExtractor;
use ;
let extractor = builder
.validator
.mapper
.build?;
The extractor maps:
user_idfrom the configuredClaimsMapperscopesfrom JWTscope(space-delimited string) andscp(array) claims, deduplicatedmetadataincluding issuer, subject, email, tenant ID, and hosted domain when present
Audit Logging
use FileAuditSink;
let audit = new?;
let middleware = with_audit;
Output:
Implement the AuditSink trait for custom destinations (database, external service, etc.).
Error Types
| Type | When |
|---|---|
AccessDenied |
RBAC check fails (user lacks permission) |
AuthError |
Role not found, audit sink failure |
ScopeDenied |
Scope check fails (missing required scopes) |
TokenError |
JWT validation failure (expired, bad signature, missing claims) |
SsoError |
Token validation or access denied in SSO flow |
Examples
Examples live in the adk-playground repo:
Security Notes
- Prefer short-lived access tokens and rotate signing keys regularly.
- The JWKS cache refreshes hourly by default; lower the refresh interval with
JwksCache::with_refresh_interval()if your IdP rotates keys aggressively. OidcProvider::from_discovery()rejects discovery documents whoseissuerdoes not match the requested issuer URL.- Token revocation and blacklist checks are not built in. If you need immediate revocation, enforce it in a custom
TokenValidatoror request extractor. JwtValidatorrejects symmetric algorithms (HS256/HS384/HS512) and EdDSA — only RSA and EC algorithms are supported with JWKS-based validation.
License
Apache-2.0
Part of ADK-Rust
This crate is part of the ADK-Rust framework for building AI agents in Rust.