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:

  • 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 (OAuth-like authorization code flow)
  • 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)

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 OAuth-like authorization code flow with user consent:

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

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

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.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.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.md for detailed documentation.

Phase 4: User Delegation

  • Auth servers issue request_token when user consent is required
  • Agents redirect users to auth server's authorization endpoint
  • Users authenticate and grant consent
  • Auth server redirects back with authorization code
  • Agents exchange code for auth tokens with sub claim

See PHASE4.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.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.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.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.0.tar.gz (97.9 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.0-py3-none-any.whl (42.1 kB view details)

Uploaded Python 3

File details

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

File metadata

  • Download URL: aauth-0.1.0.tar.gz
  • Upload date:
  • Size: 97.9 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.0.tar.gz
Algorithm Hash digest
SHA256 2a970dc435199e7276759351b4675254d3d130df5695f25a25379540771dce7f
MD5 24ec4ab45aacd822addaac6ff62ba4e7
BLAKE2b-256 3bcdcd10c6b4669d8d9cc620bf3fe133d03efde88b81cb655483818b05b92096

See more details on using hashes here.

File details

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

File metadata

  • Download URL: aauth-0.1.0-py3-none-any.whl
  • Upload date:
  • Size: 42.1 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.0-py3-none-any.whl
Algorithm Hash digest
SHA256 04809ab3321f0658b5656ead89edda3a36db6b68fcc490b40428bf3a9c77e8d7
MD5 66ad491f2d527d8b2a01cee36ad8fb06
BLAKE2b-256 99163b9d4f92852f8b420ddaee9c927be3975989af6ee635edfdec92791bb023

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