common-access-token 0.1.5

Rust implementation of Common Access Token (CAT) with HMAC signatures
Documentation
# Common Access Token (CAT) for Rust

[![Crate](https://img.shields.io/crates/v/common-access-token.svg)](https://crates.io/crates/common-access-token)
[![Documentation](https://docs.rs/common-access-token/badge.svg)](https://docs.rs/common-access-token)
[![License: MIT](https://img.shields.io/badge/License-MIT-blue.svg)](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