use hessra_cap::{CListPolicy, CapabilityEngine, Designation, IdentityConfig, ObjectId, Operation};
use hessra_cap_token::DesignationBuilder;
use hessra_identity_token::{add_identity_attenuation_to_token, inspect_identity_token};
use hessra_token_core::TokenTimeConfig;
fn main() -> Result<(), Box<dyn std::error::Error>> {
let root_policy = CListPolicy::from_toml(
r#"
[[objects]]
id = "service:webapp"
can_delegate = true
capabilities = [
{ target = "api:users", operations = ["read", "write"] },
{ target = "api:orders", operations = ["read"] },
{ target = "api:admin", operations = ["read", "write"] },
]
"#,
)?;
let root_engine = CapabilityEngine::with_generated_keys(root_policy);
let webapp_policy = CListPolicy::from_toml(
r#"
[[objects]]
id = "user:alice"
capabilities = [
{ target = "api:users", operations = ["read"] },
{ target = "api:orders", operations = ["read"] },
]
[[objects]]
id = "user:bob"
capabilities = [
{ target = "api:users", operations = ["read", "write"] },
]
"#,
)?;
let webapp_engine = CapabilityEngine::with_generated_keys(webapp_policy);
println!("=== Webapp Auth: Capability Composition ===\n");
println!("--- Step 1: Root issues service identity and capability ---");
let webapp_identity = root_engine.mint_identity(
&ObjectId::new("service:webapp"),
IdentityConfig {
delegatable: true,
..Default::default()
},
)?;
root_engine.verify_identity(&webapp_identity, &ObjectId::new("service:webapp"))?;
println!("Root issued and verified identity for service:webapp");
let service_cap = root_engine
.mint_capability(
&ObjectId::new("service:webapp"),
&ObjectId::new("api:users"),
&Operation::new("read"),
None,
)?
.token;
root_engine.verify_capability(
&service_cap,
&ObjectId::new("api:users"),
&Operation::new("read"),
)?;
println!("Root issued api:users:read capability to service:webapp\n");
println!("--- Step 2: Same-engine designations ---");
let designated = root_engine.mint_designated_capability(
&ObjectId::new("service:webapp"),
&ObjectId::new("api:users"),
&Operation::new("read"),
&[Designation {
label: "tenant_id".into(),
value: "acme-corp".into(),
}],
None,
)?;
root_engine.verify_designated_capability(
&designated.token,
&ObjectId::new("api:users"),
&Operation::new("read"),
&[Designation {
label: "tenant_id".into(),
value: "acme-corp".into(),
}],
)?;
println!("Tenant-scoped token verified for acme-corp");
let wrong_tenant = root_engine.verify_designated_capability(
&designated.token,
&ObjectId::new("api:users"),
&Operation::new("read"),
&[Designation {
label: "tenant_id".into(),
value: "evil-corp".into(),
}],
);
assert!(wrong_tenant.is_err());
println!("Wrong tenant (evil-corp) correctly rejected\n");
println!("--- Step 3: Identity delegation ---");
let root_public_key = root_engine.public_key();
let user_subject = "service:webapp:acme-corp:alice";
let delegated_identity = add_identity_attenuation_to_token(
webapp_identity.clone(),
user_subject.to_string(),
root_public_key,
TokenTimeConfig::default(),
)?;
println!("Service delegated identity to {user_subject}");
let inspect = inspect_identity_token(delegated_identity.clone(), root_public_key)?;
assert!(inspect.is_delegated);
assert!(!inspect.is_expired);
println!(
"Delegated identity verified: delegated={}, identity={}",
inspect.is_delegated, inspect.identity
);
println!("\n--- Step 4: Cross-engine delegation via DesignationBuilder ---");
let broad_token = root_engine
.mint_capability(
&ObjectId::new("service:webapp"),
&ObjectId::new("api:users"),
&Operation::new("read"),
None,
)?
.token;
let user_token = DesignationBuilder::from_base64(broad_token, root_public_key)?
.designate("tenant_id".into(), "acme-corp".into())
.designate("user".into(), user_subject.into())
.attenuate_base64()?;
println!("Webapp narrowed root token for {user_subject} at tenant acme-corp");
let user_designations = vec![
Designation {
label: "tenant_id".into(),
value: "acme-corp".into(),
},
Designation {
label: "user".into(),
value: user_subject.into(),
},
];
root_engine.verify_designated_capability(
&user_token,
&ObjectId::new("api:users"),
&Operation::new("read"),
&user_designations,
)?;
println!("API verified: alice can read api:users (correct tenant + user)");
let wrong_user = root_engine.verify_designated_capability(
&user_token,
&ObjectId::new("api:users"),
&Operation::new("read"),
&[
Designation {
label: "tenant_id".into(),
value: "acme-corp".into(),
},
Designation {
label: "user".into(),
value: "service:webapp:acme-corp:mallory".into(),
},
],
);
assert!(wrong_user.is_err());
println!("Token bound to alice -- rejected for mallory\n");
println!("--- Step 5: Webapp-level authorization (defense in depth) ---");
let alice_read = webapp_engine.evaluate(
&ObjectId::new("user:alice"),
&ObjectId::new("api:users"),
&Operation::new("read"),
None,
);
assert!(alice_read.is_granted());
println!("Webapp policy: alice CAN read api:users");
let alice_write = webapp_engine.evaluate(
&ObjectId::new("user:alice"),
&ObjectId::new("api:users"),
&Operation::new("write"),
None,
);
assert!(!alice_write.is_granted());
println!("Webapp policy: alice CANNOT write api:users (restricted by webapp policy)");
let bob_write = webapp_engine.evaluate(
&ObjectId::new("user:bob"),
&ObjectId::new("api:users"),
&Operation::new("write"),
None,
);
assert!(bob_write.is_granted());
println!("Webapp policy: bob CAN write api:users");
let bob_orders = webapp_engine.evaluate(
&ObjectId::new("user:bob"),
&ObjectId::new("api:orders"),
&Operation::new("read"),
None,
);
assert!(!bob_orders.is_granted());
println!("Webapp policy: bob CANNOT read api:orders (not in bob's grants)\n");
println!("--- Summary ---");
println!("Root engine: broad service-level capabilities (api:users, api:orders, api:admin)");
println!("Webapp engine: user-level policy as defense in depth");
println!(
"Cross-engine: DesignationBuilder narrows root tokens per-user (no signing key needed)"
);
println!("Guarantee: capabilities only narrow, never expand");
Ok(())
}