This is a high-performance, secure Java library for creating and verifying authorization tokens based on the Capability-Based Access Control (CapBAC) model. It uses advanced BLS Aggregate Signatures to ensure token integrity and provide highly efficient verification.
The library is designed with a clean, high-level API that abstracts away cryptographic complexity, making it easy to integrate a robust and modern authorization system into your application.
The library is built on a few key concepts that work together to create a flexible and secure trust model.
Instead of checking an Access Control List (ACL) to see if a user has permission, the user presents a token (a capability) that directly grants them a specific permission. This token is a self-contained, verifiable proof of authorization.
This is the cryptographic heart of the library. BLS signatures can be aggregated, meaning multiple signatures from different users can be combined into a single, compact signature. The magic is that this single aggregate signature can be verified against all the original signers and their messages in one single, fast operation. This makes verifying a chain of delegation extremely efficient.
The library defines a few core entities:
Principal: Represents an entity (a user, service, or device) that can hold permissions and sign tokens. It securely encapsulates the entity’s ID and their secret key.CapBACCertificate: A delegation token. It represents aPrincipalgranting a specific capability to anotherPrincipal. It is a verifiable proof of delegation.CapBACInvocation: An action token. It is created when aPrincipaluses a delegated capability. It contains the full delegation chain plus a final invocation record, all bound together by an aggregate signature.
- High Performance: Uses BLS aggregate signatures for extremely fast verification of complex delegation chains.
- Strong Security: The aggregate signature makes the entire token cryptographically tamper-proof. The
Principalclass prevents secret key leakage. - Clean, High-Level API: The
CapBACclass provides simple, intuitive methods (forgeCertificate,delegateCertificate,invoke) that handle all the underlying cryptographic complexity. - Flexible Capability Model: Supports arbitrary permission types through a
CapabilityCodecinterface, allowing you to define simple string-based permissions or complex, structured capabilities. - Attenuation Enforcement: Capabilities are checked for valid attenuation at both creation time and verification time via the
AttenuationCheckerinterface, preventing privilege escalation in delegation chains. - Implicit Revocation Model: Revocation is handled by removing a
Principal’s public key from theResolver, providing an immediate and simple way to invalidate all tokens signed by that principal.
Using the library is straightforward. The main entry point is the CapBAC class.
Here’s a complete example of a root entity delegating a permission to an intermediate entity, who then delegates a more specific permission to a final user, who then invokes it.
// 1. Setup the environment and Principals
CapBACScheme scheme = CapBACScheme.MIN_PK;
// Define how capabilities are decoded from bytes
CapabilityCodec<StringCapability> codec = new StringCapabilityCodec();
// Define the attenuation rule: a child capability must be
// a refinement (prefix) of its parent
AttenuationChecker<StringCapability> checker =
(parent, child) -> child.getValue().startsWith(parent.getValue());
// The CapBAC API is generic over the capability type and enforces
// attenuation at both creation time and verification time
CapBAC<StringCapability> api = new CapBAC<>(scheme, codec, checker);
// In a real app, you would load or retrieve these, not generate them.
Principal root = new Principal(scheme);
Principal intermediate = new Principal(scheme);
Principal user = new Principal(scheme);
// The resolver would typically be backed by a database.
Resolver resolver = id -> { /* ... logic to get public key for an id ... */ };
TrustChecker trustChecker = id -> id.equals(root.getId());
long expiration = Instant.now().getEpochSecond() + 3600; // Expires in 1 hour
// 2. The Root forges the initial certificate for the intermediate principal
StringCapability readCapability = new StringCapability("read");
CapBACCertificate rootCertificate = api.forgeCertificate(
root,
intermediate.getId(),
readCapability,
expiration
);
// The certificate is valid and can be passed to the intermediate principal.
assertTrue(rootCertificate.verify(resolver, trustChecker, codec, checker));
// 3. The Intermediate Principal delegates a more specific capability to the User
// "read:/data/file.txt" starts with "read", so attenuation is valid.
// Trying to delegate a broader capability (e.g. "write") would throw
// IllegalArgumentException.
StringCapability fileCapability = new StringCapability("read:/data/file.txt");
CapBACCertificate delegatedCertificate = api.delegateCertificate(
intermediate,
rootCertificate,
user.getId(),
fileCapability,
expiration
);
// This new certificate is also valid and contains the full chain of trust.
assertTrue(delegatedCertificate.verify(resolver, trustChecker, codec, checker));
// 4. The User invokes the capability
CapBACInvocation invocationToken = api.invoke(
user,
delegatedCertificate,
fileCapability, // The user invokes the specific capability they were granted
expiration
);
// The final invocation token is presented to a service for verification.
// The service can verify the entire chain and the invocation in one step.
assertTrue(invocationToken.verify(resolver, trustChecker, codec, checker));The AttenuationChecker interface prevents privilege escalation in delegation chains. Each delegated or invoked capability must be a valid attenuation (a subset or refinement) of its parent capability. This is enforced in two places:
- At creation time:
delegateCertificate()andinvoke()check the new capability against the parent and throwIllegalArgumentExceptionif attenuation is violated. - At verification time:
verify()walks the full chain and checks every parent-child capability pair, returningfalseif any step escalates privileges.
You define the attenuation rule by implementing AttenuationChecker. For example, a prefix-based rule where "read:/data/file.txt" is a valid attenuation of "read" but "write" is not.
The library uses an implicit revocation model. Revocation is handled by the Resolver interface. In a production environment, the Resolver would be backed by a database or another key store. To revoke a Principal, you simply remove their public key from this store. Any subsequent attempt to verify a token signed by that Principal will fail because the resolver can no longer provide their public key.
The tokens include an expiration timestamp to mitigate replay attacks. For systems requiring higher security, it is recommended to embed a nonce or unique ID within the Capability object itself. The verifying service would then be responsible for tracking seen nonces to ensure a token can only be used once.
The src/test/java/dev/dotfox/capbac/examples/ directory contains self-contained example tests that demonstrate real-world use cases:
AuthenticationExampleTest: User registration via proof-of-key, API token issuance, bot delegation, and revocation.DeviceManufacturingExampleTest: 3-hop supply chain (manufacturer → factory → batch → device) with hierarchical revocation.SmartHomeExampleTest: Time-limited guest access with expiry, attenuation enforcement, and chain invalidation.MicroserviceAuthExampleTest: Service-to-service auth with resource + action capabilities and least-privilege delegation.DocumentSharingExampleTest: Ordinal permission hierarchy (EDIT → COMMENT → VIEW) with cascading revocation.
Each example defines its own Capability type, CapabilityCodec, and AttenuationChecker as inner classes, and runs under both MIN_PK and MIN_SIG schemes.
The binary wire format for CapBACCertificate and CapBACInvocation tokens is documented in docs/serialization-format.md.
The project uses Maven.
- To build the JAR file:
mvn clean package - To run the test suite:
mvn test
- blst: A high-performance BLS signature library (vendored with Java bindings).