Skip to main content

Crate aauth_protocol

Crate aauth_protocol 

Source
Expand description

AAuth (draft-hardt-oauth-aauth-protocol) for Rust: how an agent proves who it is, and what a person has allowed it to do, on every request.

Every AAuth request is signed with an RFC 9421 HTTP Message Signature under the AAuth profile, and names the signer’s key in Signature-Key (draft-hardt-httpbis-signature-key). Usually the key is a JWT whose cnf.jwk is the signing key: an agent token from the agent’s provider, a person token from the person’s Person Server, or an auth token the Person Server issued for one resource. This crate is the part of the protocol every role shares:

ModuleWhat it does
keys, jwk, jwtEd25519 signing keys, public JWKs and RFC 7638 thumbprints, compact JWS
httpsigSign a request; verify one and learn which key signed it
tokenMint tokens; verify one against its issuer’s keys and the request’s signer
discoveryFind an issuer’s keys through its metadata document, over a discovery::Fetch you choose
resourceA resource’s side: resource::authenticate a request, mint resource tokens, challenge
requirementThe AAuth-Requirement header
mission, budgetWhat a person approved, and what it may spend
clientThe agent’s side of a Person Server conversation, and an SSRF guard (feature client)

The Person Server itself is the aauth-person-server crate.

§A request, end to end

An agent provider vouches for an agent’s key; the agent signs a request with it; a resource verifies the signature and the token.

use std::sync::Arc;

use aauth_protocol::discovery::{JwksResolver, StaticFetch};
use aauth_protocol::httpsig::{header_map, sign_jwt, Incoming, Outgoing, VerifyOptions};
use aauth_protocol::resource::authenticate;
use aauth_protocol::token::{mint, TokenKind};
use aauth_protocol::SigningKey;
use serde_json::json;

// The agent provider publishes its keys and vouches for the agent's.
let provider = SigningKey::generate();
let agent = SigningKey::generate();
let now = aauth_protocol::now_unix();
let agent_token = mint(&provider, TokenKind::Agent, &json!({
    "iss": "https://agents.example",
    "dwk": "aauth-agent.json",
    "sub": "aauth:travel@agents.example",
    "iat": now,
    "exp": now + 3600,
    "cnf": { "jwk": agent.public_jwk() },
}));

// The agent signs its request.
let body = br#"{"offer_id":"fl-qf1"}"#;
let signed = sign_jwt(&agent, &agent_token, &Outgoing {
    method: "POST",
    url: "https://api.booking.example/v1/reserve",
    content_type: None,
    body: Some(body),
    created: now,
})?;

// The resource verifies it, finding the provider's keys by discovery.
// `StaticFetch` stands in for the network here; use `ReqwestFetch`.
let documents = StaticFetch::new();
documents.insert(
    "https://agents.example/.well-known/aauth-agent.json",
    json!({ "issuer": "https://agents.example", "jwks": provider.jwks() }),
);
let resolver = JwksResolver::new(Arc::new(documents));
let headers = header_map(&signed)?;
let request = Incoming {
    method: "POST",
    authority: "api.booking.example",
    path: "/v1/reserve",
    query: None,
    headers: &headers,
    body: Some(body),
};
let authenticated = authenticate(
    &request,
    "https://api.booking.example",
    &[TokenKind::Agent],
    &VerifyOptions::default(),
    &resolver,
)
.await?;
assert_eq!(authenticated.token.sub, "aauth:travel@agents.example");
assert_eq!(authenticated.signature.thumbprint, agent.thumbprint());

§Features

  • client (default): client, and discovery::ReqwestFetch. Without it the crate makes no network calls of its own and pulls in no HTTP client or async runtime.

§Status

This implements -11 of the protocol draft. Signing is Ed25519; verification accepts Ed25519 and ES256. The jwt, jwks_uri and hwk Signature-Key schemes are supported, jkt-jwt and x509 are not, and revocation is not checked. Until 1.0 the API may change between minor versions.

Re-exports§

pub use budget::Budget;
pub use error::Error;
pub use error::Result;
pub use error::SignatureError;
pub use error::TokenError;
pub use jwk::Jwk;
pub use keys::SigningKey;
pub use requirement::Requirement;
pub use token::TokenKind;
pub use token::VerifiedToken;

Modules§

budget
Budgets (draft-hardt-aauth-budgets): an amount a mission may spend, and what one request costs.
clientclient
The agent’s HTTP side: a client for its Person Server, and the guard a client resolves through when the URLs it calls come from someone else.
discovery
Key discovery: {iss}/.well-known/{dwk} names a jwks_uri (or carries jwks), and the key a token or signature names is found there.
error
Errors. A signature or token that does not verify carries the registered code a peer is answered with; everything else is an Error variant naming what kind of thing went wrong.
httpsig
RFC 9421 HTTP Message Signatures under the AAuth profile (AAuth §HTTP Message Signatures), with the signer’s key named in Signature-Key (draft-hardt-httpbis-signature-key).
identifier
Server identifiers (AAuth §Server Identifiers) and origin comparison.
jwk
Public JWKs: RFC 7638 thumbprints, algorithm determination by the alg member alone (draft-hardt-httpbis-signature-key §Algorithm Determination, RFC 9864), and signature verification for the algorithms AAuth uses.
jwt
Compact JWS: minting with a SigningKey and verifying against a Jwk, under fully-specified algorithms only.
keys
The Ed25519 keys this crate signs with: an agent’s session key, which its agent token’s cnf.jwk binds, and a server’s token-signing key.
metadata
Metadata documents, published at {issuer}/.well-known/{dwk}.
mission
Missions (AAuth §Mission): what a person approved an agent to do. A mission is named everywhere afterwards by its s256, the hash of its exact bytes, so nobody can change what was approved without changing its name.
requirement
The AAuth-Requirement response header (AAuth §Requirement Responses): what a resource or server needs before it will answer.
resource
The resource’s side: authenticating a signed request, minting resource tokens, and challenging for what is missing.
token
Agent, person and auth tokens: minting, and verification as AAuth §Request-Context Binding prescribes. A port of @aauth/resource’s verifyToken, in its order: structure first, then the key binding, then the issuer’s signature, and only then anything the claims say.

Constants§

PROTOCOL_DRAFT
The protocol draft this crate implements.

Functions§

constant_time_eq
Whether a equals b, in time that depends on their lengths alone: for a secret a peer presents, such as a thumbprint or a bearer token.
now_unix
Seconds since the Unix epoch.
s256
BASE64URL(SHA-256(bytes)), unpadded: the encoding every *_s256 value uses.