Skip to main content

AAuth protocol implementation for Python

Project description

AAuth Protocol Implementation

A Python implementation of the AAuth protocol for learning and understanding the protocol through hands-on coding.

Library Installation

This project includes a reusable aauth Python library that can be installed and used in other projects.

Installing in the Current Project

If you're working within this project:

# Install in editable mode (recommended for development)
pip install -e .

# Or install normally
pip install .

Installing in Other Projects on the Same Computer

To use this library in other projects on the same computer:

  1. Navigate to your other project directory:

    cd /path/to/your/other/project
    
  2. Activate your project's virtual environment:

    # If using venv
    source .venv/bin/activate  # or venv/bin/activate
    
    # If using conda
    conda activate your-env-name
    
  3. Install the library in editable mode using the absolute path:

    pip install -e /Users/christian.posta/dev/code/aauth
    

    Or if you're in a different location, use the full path to this project:

    pip install -e /full/path/to/aauth/project
    
  4. Verify the installation:

    pip list | grep aauth
    python -c "import aauth; print(aauth.__file__)"
    

    The __file__ should point to the source directory, confirming editable mode.

  5. Use the library in your code:

    import aauth
    
    # Now you can use all the library functions
    private_key, public_key = aauth.generate_ed25519_keypair()
    

Note: Editable mode (-e) means changes to the library source code will be immediately available in your other projects without reinstalling. This is ideal for development.

Once installed, you can import and use the library:

import aauth

# Generate a key pair
private_key, public_key = aauth.generate_ed25519_keypair()

# Sign a request
signed_headers = aauth.sign_request(
    method="GET",
    target_uri="https://resource.example/api/data",
    headers={},
    body=None,
    private_key=private_key
)

# Verify a signature
is_valid = aauth.verify_signature(
    method="GET",
    target_uri="https://resource.example/api/data",
    headers=signed_headers,
    body=None,
    signature_input_header=signed_headers["Signature-Input"],
    signature_header=signed_headers["Signature"],
    signature_key_header=signed_headers["Signature-Key"]
)

See the Library Usage section below for more examples.

Overview

This project implements the AAuth protocol incrementally, phase by phase. See DEMOS.md for how each demo_phase*.py maps to SPEC_UPDATED.md and which spec areas are not yet demoed.

  • Phase 1: Pseudonymous flow (proof-of-possession without identity)
  • Phase 2: Agent identity (JWKS-based identity verification)
  • Phase 3: Autonomous authorization (full token flow)
  • Phase 4: User delegation (202 + pending URL, interaction code, polling — SPEC_UPDATED Section 4.5.4)
  • Phase 5: Agent is Resource (SSO and unified token flow)
  • Phase 6: Agent Delegation (agent tokens for distributed instances)
  • Phase 7: Token Exchange (multi-hop resource access with delegation chain)
  • Phase 8: Clarification Chat (deferred polling with clarification responses)
  • Phase 9: Interaction Chaining (downstream interaction bubbled via Resource 1)

Quick Start

Setup

  1. Install dependencies:
# (Recommended) Use virtual environment
python3 -m venv .venv
source .venv/bin/activate


pip install -r requirements.txt

Running Demos

Phase 1: Pseudonymous Flow

Demonstrates basic proof-of-possession without identity using sig=hwk scheme:

python demo_phase1.py

Phase 2: Agent Identity via JWKS

Demonstrates agent identity verification using sig=jwks scheme:

python demo_phase2.py

Phase 3: Autonomous Authorization

Demonstrates complete token flow without user interaction:

python demo_phase3.py

Phase 4: User Delegation

Demonstrates user-authorized access: resource challenge, token endpoint 202 + pending URL, user interaction at /interact, agent polling for auth_token (no OAuth authorization code):

Automated mode (uses user simulator):

python demo_phase4.py

Manual mode (browser-based testing):

python demo_phase4.py --manual

Phase 5: Agent is Resource

Demonstrates agent authenticating users to itself for SSO and API access:

Automated mode (uses user simulator):

python demo_phase5.py

Manual mode (browser-based testing):

python demo_phase5.py --manual

Phase 6: Agent Delegation

Demonstrates agent delegation where agent servers issue agent tokens to delegates:

Automated mode:

python demo_phase6.py

Phase 7: Token Exchange

Demonstrates multi-hop resource access where a resource exchanges an upstream auth token to access a downstream resource:

Automated mode:

python demo_phase7.py

Phase 8: Clarification Chat

Demonstrates deferred polling with clarification questions during consent, and agent POST clarification responses to the pending URL:

Automated mode:

python demo_phase8.py

Phase 9: Interaction Chaining

Demonstrates downstream interaction bubbling via Resource 1, keeping downstream interaction details opaque to the agent:

Automated mode:

python demo_phase9.py

Testing

Run all tests:

pytest tests/ -v

Run tests for a specific phase:

pytest tests/test_phase1.py -v
pytest tests/test_phase2.py -v
pytest tests/test_phase3.py -v
pytest tests/test_phase4.py -v
pytest tests/test_phase5.py -v
pytest tests/test_phase6.py -v
pytest tests/test_phase7.py -v
pytest tests/test_phase8.py -v
pytest tests/test_phase9.py -v

Phase Overview

Phase 1: Pseudonymous Flow

  • Agent signs requests with sig=hwk (public key in header)
  • Resource validates signatures
  • No tokens, no identity - just signature verification

See PHASE1-pop-hwk.md for detailed documentation.

Phase 2: Agent Identity via JWKS

  • Agent publishes metadata at /.well-known/aauth-agent
  • Agent publishes JWKS at /jwks.json
  • Resource can verify agent identity using sig=jwks scheme
  • Separate endpoints (/data-hwk, /data-jwks) for both schemes

See PHASE2-identity-jwks.md for detailed documentation.

Phase 3: Autonomous Authorization

  • Resources issue resource tokens when agents request access
  • Agents present resource tokens to auth servers
  • Auth servers validate resource tokens and issue auth tokens
  • Agents use auth tokens to access protected resources
  • Complete token flow without user interaction

See PHASE3-autonomous-authz.md for detailed documentation.

Phase 4: User Delegation

  • Resource returns 401 with resource token; agent POSTs to auth server token_endpoint
  • When consent is required, auth server returns 202 + Location (pending URL) + interaction code
  • User completes login/consent at /interact; agent polls pending URL until 200 with auth_token
  • No authorization code: token is delivered only via signed polling (SPEC_UPDATED Sections 10, 19.2)

See PHASE4-user-delegation.md for detailed documentation.

Phase 5: Agent is Resource

  • Agent requests authorization directly with scope (no resource_token)
  • Agent identifier matches resource identifier (agent authenticates users to itself)
  • Auth token has aud = agent identifier and agent claim omitted
  • Unified token serves both SSO (user identity) and API access purposes
  • Solves OIDC limitation where ID tokens and access tokens are separate

See PHASE5-agent-is-resource.md for detailed documentation.

Phase 6: Agent Delegation

  • Agent servers issue agent tokens (agent+jwt) to agent delegates
  • Delegates use scheme=jwt with agent tokens to sign requests
  • Resources and auth servers validate agent tokens per SPEC.md Section 5.7
  • Delegates share agent server's identity but use ephemeral keys
  • Delegate identifier (sub) persists across key rotations
  • Auth tokens include agent_delegate claim when issued to delegates

See PHASE6-agent-delegation.md for detailed documentation.

Phase 7: Token Exchange

  • Resources can act as agents to access downstream resources
  • Upstream auth tokens are exchanged for downstream auth tokens
  • Downstream auth server validates upstream token and federation trust
  • Exchanged tokens include act claim showing the delegation chain
  • User context (sub) is preserved through the chain
  • Enables autonomous multi-hop resource access

See PHASE7-token-exchange.md for detailed documentation.

Phase 8: Clarification Chat

  • Auth server can include clarification prompts in polling responses
  • Agent replies with signed POST /pending/{id} clarification responses
  • Clarification round-trips occur before user consent completes

See PHASE8-clarification-chat.md for detailed documentation.

Phase 9: Interaction Chaining

  • Resource 1 acts as an interaction broker for downstream deferred auth
  • Resource 1 returns local 202 + pending URL + interaction code to the agent
  • User enters via Resource 1 interaction endpoint and is redirected downstream
  • Resource 1 polls downstream pending URL and returns terminal outcome upstream

See PHASE9-interaction-chaining.md for detailed documentation.

Running Individual Participants

Run Resource Server:

python -m participants.resource

Run Agent:

python -m participants.agent

Run Auth Server:

python -m participants.auth_server

Library Usage

The aauth library provides a framework-agnostic implementation of the AAuth protocol. Here are some common usage patterns:

Key Generation

import aauth

# Generate Ed25519 key pair
private_key, public_key = aauth.generate_ed25519_keypair()

# Convert to JWK format
jwk = aauth.public_key_to_jwk(public_key, kid="key-1")

# Calculate JWK thumbprint
thumbprint = aauth.calculate_jwk_thumbprint(jwk)

HTTP Message Signing

import aauth

# Sign a request with hwk scheme (pseudonymous)
signed_headers = aauth.sign_request(
    method="GET",
    target_uri="https://resource.example/api/data",
    headers={"Host": "resource.example"},
    body=None,
    private_key=private_key,
    sig_scheme="hwk"
)

# Sign with jwks scheme (agent identity)
signed_headers = aauth.sign_request(
    method="POST",
    target_uri="https://resource.example/api/data",
    headers={"Content-Type": "application/json"},
    body=b'{"key": "value"}',
    private_key=private_key,
    sig_scheme="jwks",
    id="https://agent.example",
    kid="key-1"
)

# Sign with jwt scheme (using auth token)
signed_headers = aauth.sign_request(
    method="GET",
    target_uri="https://resource.example/api/data",
    headers={},
    body=None,
    private_key=private_key,
    sig_scheme="jwt",
    jwt=auth_token
)

Signature Verification

import aauth

# Verify a signature
is_valid = aauth.verify_signature(
    method=request.method,
    target_uri=str(request.url),
    headers=dict(request.headers),
    body=request_body,
    signature_input_header=request.headers.get("Signature-Input"),
    signature_header=request.headers.get("Signature"),
    signature_key_header=request.headers.get("Signature-Key"),
    jwks_fetcher=my_jwks_fetcher  # Required for jwks/jwt schemes
)

Token Creation and Validation

import aauth

# Create a resource token
resource_token = aauth.create_resource_token(
    iss="https://resource.example",
    aud="https://auth.example",
    agent="https://agent.example",
    agent_jkt=agent_thumbprint,
    scope="data.read data.write",
    private_key=resource_private_key,
    kid="resource-key-1"
)

# Create an auth token
auth_token = aauth.create_auth_token(
    iss="https://auth.example",
    aud="https://resource.example",
    agent="https://agent.example",
    cnf_jwk=agent_jwk,
    scope="data.read",
    private_key=auth_private_key,
    kid="auth-key-1"
)

# Verify an agent token
claims = aauth.verify_agent_token(
    token=agent_token,
    jwks_fetcher=my_jwks_fetcher,
    expected_aud="https://resource.example"
)

# Parse token claims (without verification)
claims = aauth.parse_token_claims(token)

Agent-Auth Header Parsing

import aauth

# Parse Agent-Auth challenge header
challenge = aauth.parse_agent_auth_header(
    "httpsig; identity=?1; auth-token; resource_token=\"...\"; auth_server=\"https://auth.example\""
)

# Build Agent-Auth challenge
challenge_header = aauth.build_agent_auth_challenge(
    require_signature=True,
    require_identity=True,
    require_auth_token=True,
    resource_token=resource_token,
    auth_server="https://auth.example"
)

High-Level Agent and Resource APIs

import aauth

# Agent request signer
signer = aauth.AgentRequestSigner(
    private_key=private_key,
    agent_id="https://agent.example",
    agent_token=agent_token
)

signed_headers = signer.sign_request(
    method="GET",
    target_uri="https://resource.example/api/data",
    headers={},
    body=None,
    sig_scheme="jwt"
)

# Resource request verifier
verifier = aauth.RequestVerifier(
    canonical_authorities=["resource.example:443"],
    jwks_fetcher=my_jwks_fetcher
)

result = verifier.verify_request(
    method="GET",
    target_uri="https://resource.example/api/data",
    headers=request_headers,
    body=request_body,
    require_identity=True,
    require_auth_token=True
)

if result["valid"]:
    print(f"Agent ID: {result['agent_id']}")
    print(f"Scopes: {result['scopes']}")

Framework Integration

The library is framework-agnostic. Here's an example for FastAPI:

from fastapi import FastAPI, Request
from aauth import RequestVerifier, AAuthRequest

app = FastAPI()
verifier = RequestVerifier(canonical_authorities=["api.example.com"])

@app.get("/protected")
async def protected_endpoint(request: Request):
    # Convert FastAPI request to AAuthRequest
    aauth_req = AAuthRequest.from_fastapi_request(request)
    
    # Verify signature
    result = verifier.verify_request(
        method=aauth_req.method,
        target_uri=str(request.url),
        headers=dict(request.headers),
        body=await request.body()
    )
    
    if not result["valid"]:
        return {"error": result["error"]}, 401
    
    return {"data": "protected resource", "agent": result["agent_id"]}

Project Structure

aauth/
├── aauth/             # Main library package (installable)
│   ├── signing/      # HTTP Message Signing (RFC 9421)
│   ├── keys/         # Key management and JWK operations
│   ├── tokens/       # JWT token handling
│   ├── headers/      # HTTP header parsing/building
│   ├── metadata/     # Metadata discovery
│   ├── http/         # HTTP abstraction layer
│   ├── agent/        # Agent role implementation
│   └── resource/     # Resource role implementation
├── core/             # Legacy core utilities (deprecated, use aauth.*)
├── participants/     # Protocol participants (demo implementations)
├── flows/           # Flow implementations
└── tests/           # Test suite

Documentation

Project details


Download files

Download the file for your platform. If you're not sure which to choose, learn more about installing packages.

Source Distribution

aauth-0.1.1.tar.gz (90.0 kB view details)

Uploaded Source

Built Distribution

If you're not sure about the file name format, learn more about wheel file names.

aauth-0.1.1-py3-none-any.whl (48.9 kB view details)

Uploaded Python 3

File details

Details for the file aauth-0.1.1.tar.gz.

File metadata

  • Download URL: aauth-0.1.1.tar.gz
  • Upload date:
  • Size: 90.0 kB
  • Tags: Source
  • Uploaded using Trusted Publishing? No
  • Uploaded via: twine/6.2.0 CPython/3.14.0

File hashes

Hashes for aauth-0.1.1.tar.gz
Algorithm Hash digest
SHA256 668b91b93e318141d34be844350b2972389801e8a1946301a279230ce8e1c2c9
MD5 b85554eb9516b13b9ca9c3f993cb08cd
BLAKE2b-256 dc4b97ce722f88781b765c9cdaa2aa8aec2c212ee92ddd4afe761ee15c2d28fb

See more details on using hashes here.

File details

Details for the file aauth-0.1.1-py3-none-any.whl.

File metadata

  • Download URL: aauth-0.1.1-py3-none-any.whl
  • Upload date:
  • Size: 48.9 kB
  • Tags: Python 3
  • Uploaded using Trusted Publishing? No
  • Uploaded via: twine/6.2.0 CPython/3.14.0

File hashes

Hashes for aauth-0.1.1-py3-none-any.whl
Algorithm Hash digest
SHA256 6e9780f93b995b07b0850508bfb1134e3a9861b28157212a6a0249bca64a72fd
MD5 e1d464b3311881d4f4c18423c0bb01c4
BLAKE2b-256 1816ab06fb4609634b8460bba179efbdf041316cc275c97fb9f16421bcd582ac

See more details on using hashes here.

Supported by

AWS Cloud computing and Security Sponsor Datadog Monitoring Depot Continuous Integration Fastly CDN Google Download Analytics Pingdom Monitoring Sentry Error logging StatusPage Status page