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:
| Module | What it does |
|---|---|
keys, jwk, jwt | Ed25519 signing keys, public JWKs and RFC 7638 thumbprints, compact JWS |
httpsig | Sign a request; verify one and learn which key signed it |
token | Mint tokens; verify one against its issuer’s keys and the request’s signer |
discovery | Find an issuer’s keys through its metadata document, over a discovery::Fetch you choose |
resource | A resource’s side: resource::authenticate a request, mint resource tokens, challenge |
requirement | The AAuth-Requirement header |
mission, budget | What a person approved, and what it may spend |
client | The 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, anddiscovery::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.
- client
client - 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 ajwks_uri(or carriesjwks), 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
Errorvariant 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
algmember alone (draft-hardt-httpbis-signature-key §Algorithm Determination, RFC 9864), and signature verification for the algorithms AAuth uses. - jwt
- Compact JWS: minting with a
SigningKeyand verifying against aJwk, under fully-specified algorithms only. - keys
- The Ed25519 keys this crate signs with: an agent’s session key, which its
agent token’s
cnf.jwkbinds, 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-Requirementresponse 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’sverifyToken, 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
aequalsb, 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*_s256value uses.