common-access-token 0.1.0

Rust implementation of Common Access Token (CAT) with HMAC support
Documentation

common-access-token

A Rust implementation of Common Access Token (CAT) with HMAC support, interoperable with the Node.js implementation.

Overview

This library provides functionality for generating and validating Common Access Tokens (CAT) using HMAC. CAT is a token format based on CWT (CBOR Web Token) that is used for authentication and authorization, as defined in the CTA-5007 specification.

Features

  • Generate CAT tokens with HMAC signatures using HMAC-SHA256
  • Validate CAT tokens with HMAC signatures
  • Support for standard claims (issuer, audience, expiration, etc.)
  • Fluent builder interface for constructing token claims
  • Comprehensive documentation with examples
  • Interoperable with the Node.js implementation in the node-cat directory

Usage

Generating a Token

use std::collections::HashMap;
use std::time::{SystemTime, UNIX_EPOCH};
use common_access_token::{Cat, CatOptions, CatGenerateOptions, CatValidationTypes};

fn main() -> Result<(), Box<dyn std::error::Error>> {
    // Create a key
    let key = hex::decode("403697de87af64611c1d32a05dab0fe1fcb715a86ab435f1ec99192d79569388")?;
    
    // Create a map of keys
    let mut keys = HashMap::new();
    keys.insert("Symmetric256".to_string(), key);
    
    // Create a CAT object
    let cat = Cat::new(CatOptions {
        keys,
        expect_cwt_tag: true,
    });
    
    // Get current time
    let now = SystemTime::now()
        .duration_since(UNIX_EPOCH)
        .unwrap()
        .as_secs() as i64;
    
    // Create claims using the builder pattern
    let claims = cat.claims_builder()
        .issuer("eyevinn")
        .subject("jonas")
        .audience("one")
        .expiration(now + 120)
        .issued_at(now)
        .build();
    
    // Generate a token
    let token = cat.generate(
        claims,
        CatGenerateOptions {
            token_type: CatValidationTypes::Mac,
            alg: "HS256".to_string(),
            kid: "Symmetric256".to_string(),
            generate_cwt_id: true,
        },
    )?;
    
    println!("Generated token: {}", token);
    
    Ok(())
}

Using the ClaimsBuilder

The library provides a fluent builder interface for constructing token claims:

use std::time::{SystemTime, UNIX_EPOCH};
use common_access_token::{Cat, CatOptions};

// Create a CAT instance
let cat = Cat::new(CatOptions::default());

// Get current time
let now = SystemTime::now()
    .duration_since(UNIX_EPOCH)
    .unwrap()
    .as_secs() as i64;

// Build claims using the fluent interface
let claims = cat.claims_builder()
    .issuer("my-service")
    .subject("user-123")
    .audience("api-gateway")        // Single audience
    // .audiences(vec!["api-1", "api-2"])  // Multiple audiences
    .expiration(now + 3600)         // Valid for 1 hour
    .not_before(now)                // Valid starting now
    .issued_at(now)                 // Issued now
    .token_id("unique-token-id")    // Custom token ID
    .cat_version(1)                 // CAT version
    .claim("custom_claim", "value") // Custom claim
    .build();

Validating a Token

use std::collections::HashMap;
use common_access_token::{Cat, CatOptions, CatValidationOptions, CatValidationTypes};

fn main() -> Result<(), Box<dyn std::error::Error>> {
    // Get the token from somewhere
    let token = "...";
    
    // Create a key
    let key = hex::decode("403697de87af64611c1d32a05dab0fe1fcb715a86ab435f1ec99192d79569388")?;
    
    // Create a map of keys
    let mut keys = HashMap::new();
    keys.insert("Symmetric256".to_string(), key);
    
    // Create a CAT object
    let cat = Cat::new(CatOptions {
        keys,
        expect_cwt_tag: true,
    });
    
    // Validate the token
    let result = cat.validate(
        token,
        CatValidationTypes::Mac,
        CatValidationOptions {
            issuer: "eyevinn".to_string(),
            audience: Some(vec!["one".to_string()]),
        },
    )?;
    
    // Check the result
    if result.is_valid() {
        println!("Token is valid!");
        if let Some(claims) = result.claims() {
            println!("Claims: {:#?}", claims);
        }
    } else {
        println!("Validation failed: {:?}", result.error);
    }
    
    Ok(())
}

Interoperability

This library is designed to be interoperable with the Node.js implementation of the Common Access Token specification found in the node-cat directory. Tokens generated by this Rust implementation can be validated by the Node.js implementation, and vice versa.

Interoperability Testing

We've implemented interoperability tests to ensure compatibility between the Rust and Node.js implementations. These tests:

  1. Generate a token with Rust and validate it with Node.js
  2. Generate a token with Node.js and validate it with Rust

There are two ways to run the interoperability tests:

Method 1: Using Cargo with the interop feature

This method runs the Rust-side interoperability tests:

# Make sure the Node.js implementation is built first
cd ../node-cat && npm install && npm run build
cd ../rust-cat

# Run the tests with the interop feature enabled
cargo test --features interop

Method 2: Using the verification script

For a comprehensive test that shows the tokens being generated and validated between the two implementations:

# From the root directory
./verify-interop.sh

This script:

  • Builds both implementations
  • Generates tokens using both implementations
  • Validates the tokens across implementations
  • Provides a clear report of the results

Running the Examples

The library includes two examples:

  1. generate.rs - Generates a CAT token
  2. validate.rs - Validates a CAT token

To run the examples:

# Generate a token
cargo run --example generate

# Validate a token
cargo run --example validate <token>

Implementation Notes

This implementation focuses on providing the core functionality needed for token creation and verification using HMAC:

  1. CBOR encoding/decoding for token serialization
  2. COSE MAC structure creation and verification with HMAC-SHA256
  3. CWT tag wrapping for compatibility with other implementations
  4. Claim validation including expiration, issuer, and audience checks
  5. Fluent builder interface for constructing token claims

While not as feature-complete as the Node.js implementation, it provides the necessary functionality for token creation and validation that can interoperate with the Node.js implementation.

License

This project is licensed under the MIT License - see the LICENSE file for details.