OAuth 2.0 settlement scopes for agent economic authorization — extends identity tokens with spending limits, counterparty policies, and delegation chains for the A2A Settlement Exchange.
Project description
A2A Settlement Auth
OAuth 2.0 settlement scopes for agent economic authorization.
Extends OAuth tokens with the missing economic layer: not just what can this agent access? but what can this agent spend?
┌──────────────────┐ OAuth Token ┌──────────────┐
│ Identity Provider│──── with settlement ─────►│ A2A-SE │
│ (Keycloak, Auth0,│ scopes & claims │ Exchange │
│ Okta, Azure AD) │ │ │
└──────────────────┘ └──────┬───────┘
│
Standard OAuth scopes: │ Middleware validates:
settlement:transact │ ✓ Scope sufficiency
settlement:escrow:create │ ✓ Spending limits
settlement:escrow:release │ ✓ Counterparty policy
│ ✓ Delegation chain
Settlement claims (JWT): │ ✓ Kill switch status
- spending_limits │
- counterparty_policy ▼
- delegation_chain Agent transacts
Why This Exists
The NIST NCCoE Concept Paper on AI Agent Identity and Authorization evaluates OAuth 2.0, OpenID Connect, and SPIFFE as identity standards for agents. These standards answer who is this agent? and what systems can it access?
None of them answer: what economic commitments can this agent make?
This library bridges that gap. It extends OAuth tokens with a settlement: scope namespace and a structured claims payload that expresses spending limits, counterparty restrictions, delegation chains, and settlement method constraints. The A2A Settlement Exchange validates these tokens before processing any economic transaction.
Install
pip install a2a-settlement-auth
Quick Start
1. Issue a Settlement-Scoped Token
Your identity provider issues a token with settlement scopes and claims:
from a2a_settlement_auth import (
SettlementClaims,
SettlementScope,
SpendingLimit,
CounterpartyPolicy,
DelegationChain,
DelegationLink,
create_settlement_token,
)
claims = SettlementClaims(
agent_id="analytics-bot-7f3a",
org_id="org-acme-corp",
spending_limits=SpendingLimit(
per_transaction=500, # Max 500 tokens per escrow
per_day=5000, # Max 5000 tokens in rolling 24h
),
counterparty_policy=CounterpartyPolicy(
allowed_categories=["analytics", "nlp"],
require_min_reputation=0.7,
),
delegation=DelegationChain(
chain=[
DelegationLink(
principal="user:julie@acme.com",
delegated_at="2026-03-01T09:00:00Z",
purpose="Q1 analytics procurement",
),
],
transferable=False,
),
)
token = create_settlement_token(
claims=claims,
scopes={SettlementScope.TRANSACT},
signing_key="your-signing-key",
issuer="https://idp.acme.com",
)
2. Validate on the Exchange
from a2a_settlement_auth import validate_settlement_token
validated = validate_settlement_token(
token=token,
verification_key="your-signing-key",
audience="https://exchange.a2a-settlement.org",
)
print(validated.settlement_claims.spending_limits.per_transaction) # 500
print(validated.settlement_claims.delegation.human_principal) # user:julie@acme.com
3. Add Middleware to the Exchange
from fastapi import FastAPI
from a2a_settlement_auth import SettlementMiddleware, SettlementAuthConfig
app = FastAPI()
config = SettlementAuthConfig(
verification_key="your-signing-key",
issuer="https://idp.acme.com",
enforce_spending_limits=True,
enforce_counterparty_policy=True,
)
app.add_middleware(SettlementMiddleware, config=config)
The middleware automatically:
- Validates Bearer tokens on all settlement endpoints
- Checks scopes against endpoint requirements
- Enforces spending limits before escrow creation
- Logs authorization decisions for audit
- Attaches
request.state.settlement_tokenfor downstream handlers
4. Track Spending
from a2a_settlement_auth import SpendingTracker
tracker = SpendingTracker()
# Before authorizing an escrow
result = await tracker.check(
token_jti=validated.jti,
amount=200,
limits=validated.settlement_claims.spending_limits,
)
if not result.allowed:
raise Exception(result.reason)
# After escrow confirmed
await tracker.record(validated.jti, 200, "escrow-001", "counterparty-bot")
# Emergency kill switch
await tracker.revoke(validated.jti)
Kill Switch and IdP Integration
The kill switch revokes spending authority in the local store only (in-memory or Redis/Postgres). It does not and should not attempt to revoke the token at the IdP. The exchange is a relying party that validates tokens; it does not hold IdP admin credentials. Revoking at the IdP would also kill all access (e.g., non-settlement scopes), not just economic authority. The local blacklist is instant—the next request is denied in microseconds.
To integrate with your IdP or security orchestrator, configure revoke_webhook_url. When the kill switch fires, the exchange emits a settlement:token:revoked event to that URL. Your security team can then decide whether to revoke at the IdP, disable the agent, or monitor.
config = SettlementAuthConfig(
verification_key="your-signing-key",
revoke_webhook_url="https://your-security-hook.example.com/revoke",
)
# Requires: pip install a2a-settlement-auth[webhook]
Pattern: The kill switch stops settlement immediately; integrate with your IdP's revocation endpoint via the webhook for full token revocation.
Hierarchical Delegation
Spending limits are inherited downward and can only be narrowed, never expanded. An orchestrator with a $500/day limit can delegate to sub-agents with carved-out budgets (e.g., $50/day to a scraper, $200/day to an analyst). The sum of delegated allocations cannot exceed the parent's limit per dimension.
Each delegated token includes parent_jti linking to the delegating token, forming a tree. Use create_delegated_token (sync) or create_delegated_token_async (with SpendingTracker) to issue sub-tokens:
from a2a_settlement_auth import (
create_delegated_token_async,
validate_settlement_token,
SpendingLimit,
SpendingTracker,
)
# Parent token (orchestrator) with transferable=True
validated = validate_settlement_token(token, key, audience=audience)
tracker = SpendingTracker()
# Create delegated token for scraper with $50/day
child_token, child_jti = await create_delegated_token_async(
parent=validated,
child_agent_id="scraper-bot",
child_limits=SpendingLimit(per_day=50, per_transaction=25),
signing_key=exchange_signing_key,
issuer=exchange_url,
spending_tracker=tracker,
)
# Allocation is recorded automatically; parent's effective daily budget drops by $50
When a child token is revoked, its allocation returns to the parent's pool. Revoking a parent cascades—all descendant tokens lose economic authority instantly.
Settlement Scopes
| Scope | Description |
|---|---|
settlement:read |
View balances, history, reputation |
settlement:escrow:create |
Create escrow holds |
settlement:escrow:release |
Release escrowed funds |
settlement:escrow:refund |
Refund escrowed funds |
settlement:dispute:file |
File a dispute |
settlement:dispute:resolve |
Resolve disputes (mediator) |
settlement:transact |
Composite: create + release + refund + read |
settlement:admin |
All settlement operations |
Scopes follow OAuth 2.0 conventions. The settlement:transact composite scope expands to its constituent parts, so a token with settlement:transact is authorized for settlement:escrow:create.
Settlement Claims
Claims are namespaced under https://a2a-settlement.org/claims in the JWT payload per RFC 7519 §4.2:
{
"sub": "agent:analytics-bot-7f3a",
"scope": "settlement:transact",
"https://a2a-settlement.org/claims": {
"agent_id": "analytics-bot-7f3a",
"org_id": "org-acme-corp",
"spending_limits": {
"per_transaction": 500,
"per_day": 5000
},
"counterparty_policy": {
"allowed_categories": ["analytics", "nlp"],
"require_min_reputation": 0.7
},
"delegation": {
"chain": [{
"principal": "user:julie@acme.com",
"delegated_at": "2026-03-01T09:00:00Z",
"purpose": "Q1 analytics procurement"
}],
"transferable": false
}
}
}
Claim Reference
| Claim | Type | Description |
|---|---|---|
agent_id |
string | Agent's ID on the settlement exchange |
org_id |
string | Owning organization |
spending_limits.per_transaction |
float | Max tokens per escrow |
spending_limits.per_session |
float | Max tokens for token lifetime |
spending_limits.per_hour |
float | Max tokens per rolling hour |
spending_limits.per_day |
float | Max tokens per rolling 24h |
counterparty_policy.allowed_categories |
string[] | Permitted counterparty categories |
counterparty_policy.blocked_agents |
string[] | Denied counterparty agent IDs |
counterparty_policy.blocked_orgs |
string[] | Denied counterparty org IDs |
counterparty_policy.require_min_reputation |
float | Min reputation score (0–1) |
counterparty_policy.require_certified |
bool | Require certified counterparties |
delegation.chain |
object[] | Ordered delegation links |
delegation.transferable |
bool | Can the agent sub-delegate? |
parent_jti |
string | JTI of delegating parent (hierarchical delegation) |
settlement_methods |
string[] | Permitted methods (token, fiat) |
environment |
string | Deployment env (production, sandbox) |
certification_id |
string | Agent ATO/certification reference |
Architecture
┌─────────────────────────────────────────────────────────────────┐
│ Identity Provider (IdP) │
│ Issues OAuth tokens with settlement scopes + claims │
│ (Keycloak, Auth0, Okta, Azure AD, custom) │
└─────────────────────────────┬───────────────────────────────────┘
│ Bearer token
▼
┌─────────────────────────────────────────────────────────────────┐
│ SettlementMiddleware │
│ ┌──────────┐ ┌──────────┐ ┌──────────┐ ┌───────────────┐ │
│ │ Token │ │ Scope │ │ Spending │ │ Counterparty │ │
│ │Validator │─►│ Check │─►│ Check │─►│Policy Check │ │
│ └──────────┘ └──────────┘ └──────────┘ └───────────────┘ │
└─────────────────────────────┬───────────────────────────────────┘
│ request.state.settlement_token
▼
┌─────────────────────────────────────────────────────────────────┐
│ A2A Settlement Exchange │
│ Escrow • Release • Refund • Reputation • Disputes │
└─────────────────────────────────────────────────────────────────┘
Integration with NIST Standards
This library implements concepts from:
- NIST SP 800-207 (Zero Trust Architecture) — every settlement request is verified independently
- NIST SP 800-63-4 (Digital Identity Guidelines) — agent identity linked to human principals
- OAuth 2.0/2.1 — standard scope and token mechanisms extended for economic authorization
- NIST AI RMF (AI 100-1) — settlement monitoring as a Measure function for agent security
It is designed to complement the NIST NCCoE demonstration project on AI Agent Identity and Authorization by providing the economic authorization layer that existing identity standards do not address.
Testing
pip install -e ".[dev]"
pytest
python smoke_test.py # Full lifecycle (create→validate→spending→revoke)
python smoke_test.py -v # Same, with verbose example output
Related Projects
| Project | Description |
|---|---|
| a2a-settlement | Core settlement exchange + SDK |
| a2a-settlement-mediator | AI-powered dispute resolution |
| crewai-a2a-settlement | CrewAI framework integration |
| litellm-a2a-settlement | LiteLLM framework integration |
License
MIT
Project details
Release history Release notifications | RSS feed
Download files
Download the file for your platform. If you're not sure which to choose, learn more about installing packages.
Source Distribution
Built Distribution
Filter files by name, interpreter, ABI, and platform.
If you're not sure about the file name format, learn more about wheel file names.
Copy a direct link to the current filters
File details
Details for the file a2a_settlement_auth-0.1.0.tar.gz.
File metadata
- Download URL: a2a_settlement_auth-0.1.0.tar.gz
- Upload date:
- Size: 30.3 kB
- Tags: Source
- Uploaded using Trusted Publishing? No
- Uploaded via: twine/6.2.0 CPython/3.10.19
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
61947ed9a67010f82df66bdd17a4b37d539dad7392918bc54cc5a7677eeee52e
|
|
| MD5 |
0ed34a609240c3363a724d71c4e8dc6f
|
|
| BLAKE2b-256 |
78b5330e2ab894fb0363f29dfd185083f52506f15f4f52ee5ed2612560642c3e
|
File details
Details for the file a2a_settlement_auth-0.1.0-py3-none-any.whl.
File metadata
- Download URL: a2a_settlement_auth-0.1.0-py3-none-any.whl
- Upload date:
- Size: 26.5 kB
- Tags: Python 3
- Uploaded using Trusted Publishing? No
- Uploaded via: twine/6.2.0 CPython/3.10.19
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
7bddbeaf14195f8b021a7813dd835e94c9390fc2f95e9dd94c08474c3f5a98a1
|
|
| MD5 |
1138124e59dadf2fca2940599f3ee329
|
|
| BLAKE2b-256 |
4c58245484a997c608d5b25d83445a82b89bef99de0502ce306a94fe5073db1b
|