# Common Access Token (CAT) for Rust
[](https://crates.io/crates/common-access-token)
[](https://docs.rs/common-access-token)
[](LICENSE)
A Rust implementation of the Common Access Token (CAT) specification with HMAC signatures.
## What is CAT?
Common Access Token (CAT) is a token format designed for authorization and authentication in distributed systems, particularly for media and content delivery applications. It provides a secure, compact, and efficient way to represent claims and authorization information between parties.
CAT is built on established standards:
- Based on [CBOR Web Token (CWT)](https://tools.ietf.org/html/rfc8392) format
- Uses [CBOR Object Signing and Encryption (COSE)](https://tools.ietf.org/html/rfc8152) for cryptographic operations
- Provides a binary alternative to JWT with smaller token sizes and more efficient processing
## Overview
This library provides a complete implementation for generating and validating Common Access Tokens (CAT) using HMAC signatures. It is designed to be interoperable with other implementations like [node-cat](https://github.com/Eyevinn/node-cat).
Key benefits of using CAT tokens:
- **Compact**: Binary format results in smaller token sizes compared to text-based formats
- **Efficient**: CBOR encoding/decoding is faster and requires less processing power
- **Secure**: Built on established cryptographic standards
- **Extensible**: Supports custom claims and extensions
## Features
- **Token Operations**:
- Generate CAT tokens with HMAC signatures (HS256)
- Validate CAT tokens with comprehensive security checks
- Support for token expiration and time-based validation
- **Claims Support**:
- Standard CWT claims (issuer, subject, audience, expiration, etc.)
- CAT-specific claims (version, renewal, usage, data, authorization)
- Custom claim extension capability
- **Integration**:
- Interoperability with other CAT implementations
- Easy integration with Rust applications
- Comprehensive documentation and examples
## Installation
Add this to your `Cargo.toml`:
```toml
[dependencies]
common-access-token = "0.1"
```
## Usage
### Token Generation
This example demonstrates how to create a CAT token with standard claims:
```rust
use common_access_token::{Cat, CatGenerateOptions, CatOptions, CatValidationType, Claims};
use std::collections::HashMap;
fn main() -> Result<(), Box<dyn std::error::Error>> {
// Step 1: Set up the cryptographic key
// This is a sample key - in production, use a secure key management system
let key = hex::decode("403697de87af64611c1d32a05dab0fe1fcb715a86ab435f1ec99192d79569388")?;
let mut keys = HashMap::new();
keys.insert("Symmetric256".to_string(), key);
// Step 2: Configure the CAT instance
// expect_cwt_tag: true means the token will include the CWT tag for compatibility
let cat = Cat::new(CatOptions {
keys,
expect_cwt_tag: true,
});
// Step 3: Create claims for the token
let mut claims = Claims::new();
// Standard CWT claims
claims.set_issuer("eyevinn"); // Who issued this token
claims.set_subject("jonas"); // Who this token refers to
claims.set_audience("one"); // Who this token is intended for
// Set time-based claims
let now = std::time::SystemTime::now()
.duration_since(std::time::UNIX_EPOCH)?
.as_secs() as i64;
claims.set_expiration(now + 120); // Token expires in 2 minutes
claims.set_issued_at(now); // Token was issued now
// Step 4: Generate the token
let token = cat.generate(claims, &CatGenerateOptions {
validation_type: CatValidationType::Mac, // Use HMAC for signing
alg: "HS256".to_string(), // Use HMAC-SHA256 algorithm
kid: "Symmetric256".to_string(), // Key ID to use
generate_cwt_id: true, // Generate a unique token ID
})?;
println!("Generated token: {}", token);
// The token is base64-encoded and can be transmitted over HTTP headers, etc.
Ok(())
}
```
### Using CAT-specific Claims
CAT extends the standard CWT claims with additional fields for specific use cases:
```rust
use common_access_token::{Cat, CatGenerateOptions, CatOptions, CatValidationType, Claims};
use std::collections::HashMap;
fn main() -> Result<(), Box<dyn std::error::Error>> {
// Create a CAT instance with a cryptographic key
let cat = Cat::new(CatOptions {
keys: HashMap::from([
("Symmetric256".to_string(),
hex::decode("403697de87af64611c1d32a05dab0fe1fcb715a86ab435f1ec99192d79569388")?),
]),
expect_cwt_tag: true,
});
// Create claims with both standard and CAT-specific properties
let mut claims = Claims::new();
// Standard claims
claims.set_issuer("eyevinn");
claims.set_subject("jonas");
// Time-based claims
let now = std::time::SystemTime::now()
.duration_since(std::time::UNIX_EPOCH)?
.as_secs() as i64;
claims.set_expiration(now + 3600); // 1 hour from now
claims.set_issued_at(now);
// CAT-specific claims
claims.set_cat_version(2); // Protocol version
claims.set_cat_usage("streaming"); // Purpose of the token
claims.set_cat_data("{\"quality\":\"hd\", \"drm\":\"widevine\"}"); // Additional metadata
claims.set_cat_authorization("full_access"); // Authorization level
// Generate the token
let token = cat.generate(claims, &CatGenerateOptions {
validation_type: CatValidationType::Mac,
alg: "HS256".to_string(),
kid: "Symmetric256".to_string(),
generate_cwt_id: true,
})?;
println!("Generated token with CAT claims: {}", token);
Ok(())
}
```
### Token Validation
This example shows how to validate a CAT token and extract its claims:
```rust
use common_access_token::{Cat, CatOptions, CatValidationOptions, CatValidationType};
use std::collections::HashMap;
fn main() -> Result<(), Box<dyn std::error::Error>> {
// Step 1: Get the token to validate (typically from a request header)
let token = "..."; // Base64 encoded token received from client
// Step 2: Set up the cryptographic key for validation
// This must be the same key used to sign the token
let key = hex::decode("403697de87af64611c1d32a05dab0fe1fcb715a86ab435f1ec99192d79569388")?;
let mut keys = HashMap::new();
keys.insert("Symmetric256".to_string(), key);
// Step 3: Create a CAT instance
let cat = Cat::new(CatOptions {
keys,
expect_cwt_tag: true,
});
// Step 4: Define validation criteria
let validation_options = CatValidationOptions {
issuer: "eyevinn".to_string(), // Only accept tokens from this issuer
audience: None, // Don't validate audience (or specify allowed audiences)
};
// Step 5: Validate the token
match cat.validate(token, CatValidationType::Mac, &validation_options) {
Ok(claims) => {
// Token is valid! Extract and use the claims
println!("✅ Token is valid!");
// Standard CWT claims
println!("Issuer: {:?}", claims.get_issuer());
println!("Subject: {:?}", claims.get_subject());
println!("Audience: {:?}", claims.get_audience());
println!("Expiration: {:?}", claims.get_expiration());
println!("Issued At: {:?}", claims.get_issued_at());
// CAT-specific claims
println!("CAT Version: {:?}", claims.get_cat_version());
println!("CAT Usage: {:?}", claims.get_cat_usage_string());
println!("CAT Data: {:?}", claims.get_cat_data_string());
println!("CAT Authorization: {:?}", claims.get_cat_authorization_string());
// Now you can use these claims to make authorization decisions
}
Err(err) => {
// Token validation failed
eprintln!("❌ Token validation failed: {}", err);
// Handle the error (e.g., return 401 Unauthorized)
}
}
Ok(())
}
```
## Examples
The library includes several ready-to-use examples in the `examples/` directory:
- **generate.rs**: Demonstrates basic token generation with standard claims
- **validate.rs**: Shows how to validate tokens and extract claims
- **interop.rs**: Tests interoperability with the NodeJS implementation
- **cat_claims.rs**: Demonstrates using CAT-specific claims for advanced use cases
To run an example:
```bash
# Generate a token
cargo run --example generate
# Validate a token (replace <token> with an actual token)
cargo run --example validate <token>
# Test interoperability with NodeJS implementation
cargo run --example interop [<token>]
# Use CAT-specific claims
cargo run --example cat_claims
```
## Security Considerations
When using CAT tokens in your applications, keep these security best practices in mind:
1. **Key Management**:
- Store signing keys securely
- Rotate keys periodically
- Use different keys for different environments
2. **Token Validation**:
- Always validate tokens before trusting their contents
- Check expiration times
- Verify the issuer and audience claims
3. **Token Lifetime**:
- Use short-lived tokens when possible
- For longer sessions, consider refresh token patterns
4. **Claims**:
- Only include necessary information in tokens
- Be cautious with sensitive data in claims
## Compatibility
This library is designed to be interoperable with other CAT implementations:
- **[node-cat](https://github.com/Eyevinn/node-cat)**: The NodeJS reference implementation
- Other implementations that follow the CAT specification