9 stable releases
| 4.5.0 | Mar 30, 2026 |
|---|---|
| 4.4.0 | Mar 29, 2026 |
| 4.0.3 | Feb 22, 2026 |
#799 in Cryptography
Used in clasp-cli
230KB
5.5K
SLoC
clasp-caps
Delegatable capability tokens with Ed25519 signatures for CLASP.
Features
- Ed25519 Signatures - Tokens are cryptographically signed, no shared secrets needed
- Delegation Chains - Delegate tokens with attenuated scopes (UCAN-style)
- Scope Attenuation - Child tokens can only narrow permissions, never widen them
- Expiration Clamping - Child tokens cannot outlive their parent
- Chain Depth Limits - Configurable maximum delegation depth
- ValidatorChain Integration - Works alongside CPSK and Entity validators
Installation
[dependencies]
clasp-caps = "3.5"
Usage
Create a Root Token
use clasp_caps::CapabilityToken;
use ed25519_dalek::SigningKey;
use rand::rngs::OsRng;
// Generate a root keypair
let root_key = SigningKey::generate(&mut OsRng);
// Create a root token with admin access, valid for 24 hours
let expires = std::time::SystemTime::now()
.duration_since(std::time::UNIX_EPOCH)
.unwrap()
.as_secs() + 86400;
let root_token = CapabilityToken::create_root(
&root_key,
vec!["admin:/**".to_string()],
expires,
None, // bearer token (no audience restriction)
)?;
// Encode for transmission
let wire = root_token.encode()?; // "cap_<base64url(msgpack)>"
Delegate a Token
// Generate a child keypair
let child_key = SigningKey::generate(&mut OsRng);
// Delegate with narrower scopes -- child can only write to /lights/**
let child_token = root_token.delegate(
&child_key,
vec!["write:/lights/**".to_string()],
expires,
None,
)?;
// Delegate again with even narrower scopes
let grandchild_key = SigningKey::generate(&mut OsRng);
let grandchild_token = child_token.delegate(
&grandchild_key,
vec!["read:/lights/room1/**".to_string()],
expires,
None,
)?;
Decode and Inspect
let decoded = CapabilityToken::decode(&wire)?;
assert_eq!(decoded.chain_depth(), 0); // root token
assert!(!decoded.is_expired());
decoded.verify_signature()?;
Validate with Trust Anchors
use clasp_caps::CapabilityValidator;
let root_pubkey = root_key.verifying_key().to_bytes().to_vec();
let validator = CapabilityValidator::new(
vec![root_pubkey], // trust anchors
5, // max chain depth
);
// Implements clasp_core::security::TokenValidator
use clasp_core::security::TokenValidator;
match validator.validate(&wire) {
clasp_core::security::ValidationResult::Valid(info) => {
println!("Scopes: {:?}", info.scopes);
}
other => println!("Validation failed: {:?}", other),
}
Token Wire Format
Tokens use the cap_ prefix followed by URL-safe base64-encoded MessagePack:
cap_<base64url(msgpack(CapabilityToken))>
Delegation Chain
Root Token (issuer: KeyA, scopes: admin:/**)
│
│ delegate() -- scope attenuation enforced
▼
Child Token (issuer: KeyB, scopes: write:/lights/**)
│ proofs: [ProofLink{issuer: KeyA, scopes, sig}]
│
│ delegate() -- expiration clamped to parent
▼
Grandchild (issuer: KeyC, scopes: read:/lights/room1/**)
proofs: [ProofLink{KeyA,...}, ProofLink{KeyB,...}]
Each delegation step enforces:
- Scope subset -- child scopes must be a subset of parent scopes
- Action hierarchy --
admin > write > read(custom actions require exact match) - Pattern subset -- child patterns must be covered by parent patterns
- Expiration clamping --
child_expires = min(child_expires, parent.expires_at)
Configuration Reference
CapabilityToken
| Field | Type | Description |
|---|---|---|
version |
u8 |
Token version (currently 1) |
issuer |
Vec<u8> |
Issuer's Ed25519 public key (32 bytes) |
audience |
Option<Vec<u8>> |
Audience public key (None = bearer token) |
scopes |
Vec<String> |
Scopes in action:pattern format |
expires_at |
u64 |
Expiration as Unix timestamp (seconds) |
nonce |
String |
UUID v4 nonce for replay prevention |
proofs |
Vec<ProofLink> |
Delegation chain (empty for root tokens) |
signature |
Vec<u8> |
Ed25519 signature (64 bytes) |
CapabilityValidator
| Parameter | Type | Description |
|---|---|---|
trust_anchors |
Vec<Vec<u8>> |
Trusted root issuer public keys (32 bytes each) |
max_depth |
usize |
Maximum allowed delegation chain depth |
Action Hierarchy
| Parent Action | Allowed Child Actions |
|---|---|
admin |
admin, write, read, any custom |
write |
write, read |
read |
read only |
| custom | exact match only |
License
Licensed under either of Apache License, Version 2.0 or MIT license at your option.
Maintained by LumenCanvas
Dependencies
~4–6MB
~115K SLoC