AAuth Quickstart — Python SDK
Authenticate a Python agent using AAuth (the agent identity protocol: an agent proves who it is by signing each request with its own private key instead of sending a shared secret) with the lumoauth SDK. The agent's identity is an Ed25519 key pair registered with LumoAuth; request_authorization trades a resource token for a short-lived access token; signed_request turns every outgoing HTTP call into a signed HTTP request (a per-request, replay-proof proof that the caller holds the key).
- A LumoAuth organization (agent identity is available on every plan, nothing to switch on)
- Python 3.9+
Complete Steps 1–3 first: generate a key pair, register the agent, and register a resource.
Install
pip install 'lumoauth[aauth]'
Quick Start
from lumoauth import AAuthClient
# Generate a key pair (one-time) - or load an existing private key
private_pem, jwks = AAuthClient.generate_keypair()
# Register the **jwks** with LumoAuth in the portal, then:
client = AAuthClient(
agent_identifier="https://my-agent.example.com",
private_key_pem=private_pem, # or open("agent-key.pem").read()
org_id="acme-corp",
)
# You need two tokens first (see the AAuth Quickstart):
# agent_token — your `agent+jwt`, bound to this key pair via its cnf.jwk;
# it is presented in the Agent-Auth header.
# resource_token — obtained from the resource server you intend to call.
agent_token = "..."
resource_token = "..."
# Request authorisation (direct flow - no user interaction)
tokens = client.request_authorization(
resource_token=resource_token,
scope="read write",
agent_token=agent_token,
redirect_uri="https://my-agent.example.com/oauth/callback", # only used when consent is needed
)
if tokens.get("authorization_required"):
# User consent needed - redirect the user
print("Redirect user to:", tokens["auth_url"])
# After the user approves, exchange the code (see "Handling user consent" below)
else:
# On success the response body carries the agent access token under
# the key "auth_token" (not "access_token"). Use it as the bearer.
resp = client.signed_request(
"GET",
"https://api.example.com/v1/data",
auth_token=tokens["auth_token"],
)
print(resp.json())
Key points
| Step | What happens |
|---|---|
AAuthClient.generate_keypair() | Generates an Ed25519 key pair; register the JWKS in the portal |
request_authorization(...) | Sends a signed AAuth request; may return authorization_required for user-consent flows |
client.signed_request(...) | Sends a signed HTTP request: adds the Signature and Signature-Input headers plus Authorization: Bearer <auth_token> |
Handling user consent
When authorization_required is True, redirect the user to auth_url. After the user approves, the browser is redirected back to your redirect_uri with a code parameter. Exchange it with the same redirect URI the code was delivered to (it must match one registered for the agent):
# Exchange the authorization code for tokens
tokens = client.exchange_code(
received_code,
"https://my-agent.example.com/oauth/callback",
agent_token=agent_token,
)
resp = client.signed_request("GET", "https://api.example.com/v1/data",
auth_token=tokens["auth_token"])
Next steps
- AAuth Protocol spec — full technical details
- AAuth Quickstart — LangChain — use AAuth inside a LangGraph agent
Standards used on this page
| Plain name | Standard |
|---|---|
| Signed HTTP requests (HTTP message signatures) | RFC 9421 |
See the standards reference for what each one covers and how LumoAuth uses it.