1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
//! Canonical wire format for the Agent Capability Token (ACT).
//!
//! ANVIL section 5 requires every compliant agent to operate under a scoped
//! ACT, but no document defined the token's byte encoding. Three
//! implementations filled that gap independently and disagreed: an issuer whose
//! tokens no verifier could read, and two verifiers that agreed with each other
//! and with nothing that was actually minted. Each declared in its own
//! documentation that it matched the others.
//!
//! This crate is the single normative definition. It is vendor-neutral and
//! depends on no product crate, so an issuer and a verifier can share one
//! format without either depending on the other's implementation.
//!
//! # Format
//!
//! See [`wire`] for the envelope, and [`SPECIFICATION.md`] for the normative
//! description.
//!
//! [`SPECIFICATION.md`]: https://github.com/OpenAgentID/act/blob/main/SPECIFICATION.md
//!
//! Encoding choices follow CWT (RFC 8392) conventions where they apply -
//! integer epoch seconds for the temporal claims, a flat array for scopes, text
//! for identifiers. This is **not** an RFC 8392 implementation: claim keys are
//! text rather than the registered integer keys, and signing is raw Ed25519
//! over the claims byte string rather than COSE_Sign1. Callers needing wire
//! compatibility with a CWT library will not find it here.
//!
//! # Verifying
//!
//! ```
//! use agent_capability_token::{verify, ActError, Verifier};
//!
//! # fn main() -> Result<(), ActError> {
//! let verifier = Verifier::new(
//! vec![[0u8; 32]], // in production, loaded from the issuer's key endpoint
//! "arsenal:broker:prod-1",
//! "omerta",
//! )?
//! .requiring_scopes(["tools:calendar:invoke".parse()?])
//! .with_leeway_seconds(30);
//!
//! let token: &[u8] = &[]; // received from the gateway
//! match verify(token, &verifier) {
//! Ok(claims) => println!("authorized {}", claims.sub),
//! Err(ActError::Expired { .. }) => println!("token expired"),
//! Err(other) => println!("rejected: {other}"),
//! }
//! # Ok(())
//! # }
//! ```
//!
//! # What this crate does not do
//!
//! It carries claims and checks a token's integrity, temporal window, issuer,
//! audience and scope grant. It does not evaluate issuer policy. Rate limits,
//! spend budgets, device and network bindings and audit trace travel in
//! [`ActClaims::ext`] as opaque signed CBOR, and the components that own their
//! meaning interpret them. Restating those schemas here is exactly what caused
//! the divergence this format replaces.
pub use ;
pub use ;
pub use ;
pub use ;
pub use sign;