Token

Struct Token 

Source
pub struct Token {
    pub header: Header,
    pub claims: Claims,
    pub signature: Vec<u8>,
    /* private fields */
}
Expand description

Common Access Token structure

Fields§

§header: Header

Token header

§claims: Claims

Token claims

§signature: Vec<u8>

Token signature

Implementations§

Source§

impl Token

Source

pub fn new(header: Header, claims: Claims, signature: Vec<u8>) -> Self

Create a new token with the given header, claims, and signature

Source

pub fn to_bytes(&self) -> Result<Vec<u8>, Error>

Encode the token to CBOR bytes

Examples found in repository?
examples/cat_validation.rs (line 16)
7fn main() {
8    // Create a key for signing and verification
9    let key = b"my-secret-key-for-hmac-sha256";
10    let now = current_timestamp() as i64;
11
12    // Create a token with multiple CAT-specific claims
13    let token = create_token_with_cat_claims(key, now);
14
15    // Encode token to bytes
16    let token_bytes = token.to_bytes().expect("Failed to encode token");
17    println!(
18        "Token with CAT claims encoded to {} bytes",
19        token_bytes.len()
20    );
21
22    // Decode the token
23    let decoded_token =
24        common_access_token::Token::from_bytes(&token_bytes).expect("Failed to decode token");
25
26    // Verify signature
27    decoded_token
28        .verify(key)
29        .expect("Failed to verify signature");
30
31    // Demonstrate different CAT-specific claim validations
32    validate_catu_claim(&decoded_token);
33    validate_catm_claim(&decoded_token);
34    validate_catreplay_claim(&decoded_token);
35}
More examples
Hide additional examples
examples/cat_specific_claims.rs (line 15)
7fn main() {
8    // Create a key for signing and verification
9    let key = b"my-secret-key-for-hmac-sha256";
10
11    // Create a token with CAT-specific claims
12    let token = create_token_with_cat_claims(key);
13
14    // Encode token to bytes
15    let token_bytes = token.to_bytes().expect("Failed to encode token");
16    println!("Token encoded to {} bytes", token_bytes.len());
17
18    // Decode and verify the token
19    let decoded_token =
20        common_access_token::Token::from_bytes(&token_bytes).expect("Failed to decode token");
21
22    // Verify the signature
23    decoded_token
24        .verify(key)
25        .expect("Failed to verify signature");
26
27    // Verify the claims
28    let options = VerificationOptions::new()
29        .verify_exp(true)
30        .expected_issuer("example-issuer");
31
32    decoded_token
33        .verify_claims(&options)
34        .expect("Failed to verify claims");
35
36    // Print token information
37    print_token_info(&decoded_token);
38}
examples/basic_usage.rs (line 17)
7fn main() {
8    // Secret key for signing and verification
9    let key = b"my-secret-key-for-hmac-sha256";
10
11    // Create a token with both string and binary key ID examples
12    let string_kid_token = create_token_with_string_kid(key);
13    let binary_kid_token = create_token_with_binary_kid(key);
14    let nested_map_token = create_token_with_nested_map(key);
15
16    // Encode tokens to bytes
17    let string_kid_token_bytes = string_kid_token.to_bytes().expect("Failed to encode token");
18    let binary_kid_token_bytes = binary_kid_token.to_bytes().expect("Failed to encode token");
19    let nested_map_token_bytes = nested_map_token.to_bytes().expect("Failed to encode token");
20
21    println!(
22        "Token with string key ID encoded as {} bytes",
23        string_kid_token_bytes.len()
24    );
25    println!(
26        "Token with binary key ID encoded as {} bytes",
27        binary_kid_token_bytes.len()
28    );
29    println!(
30        "Token with nested map encoded as {} bytes",
31        nested_map_token_bytes.len()
32    );
33
34    // Decode and verify tokens
35    verify_token(&string_kid_token_bytes, key, "string-key-example");
36    verify_token(&binary_kid_token_bytes, key, "binary-key-example");
37    verify_nested_map_token(&nested_map_token_bytes, key);
38}
examples/extended_cat_claims.rs (line 234)
20fn main() {
21    let key = b"my-secret-key-for-hmac-sha256";
22    let now = current_timestamp();
23
24    println!("=== Extended CAT Claims Example ===\n");
25
26    // Example 1: Token with probability of rejection (CATPOR)
27    println!("1. Creating token with CATPOR (25% rejection probability)");
28    let token_with_catpor = TokenBuilder::new()
29        .algorithm(Algorithm::HmacSha256)
30        .protected_key_id(KeyId::string("key-1"))
31        .registered_claims(
32            RegisteredClaims::new()
33                .with_issuer("example-issuer")
34                .with_expiration(now + 3600),
35        )
36        .custom_cbor(cat_keys::CATPOR, catpor::create(25))
37        .sign(key)
38        .expect("Failed to sign token");
39
40    println!("   ✓ Token created with CATPOR: 25% rejection probability\n");
41
42    // Example 2: Token with network IP restrictions (CATNIP)
43    println!("2. Creating token with CATNIP (IP restrictions)");
44    let token_with_catnip = TokenBuilder::new()
45        .algorithm(Algorithm::HmacSha256)
46        .protected_key_id(KeyId::string("key-2"))
47        .registered_claims(
48            RegisteredClaims::new()
49                .with_issuer("example-issuer")
50                .with_expiration(now + 3600),
51        )
52        .custom_array(
53            cat_keys::CATNIP,
54            catnip::create(vec!["192.168.1.0/24", "10.0.0.0/8"]),
55        )
56        .sign(key)
57        .expect("Failed to sign token");
58
59    println!("   ✓ Token created with CATNIP: 192.168.1.0/24, 10.0.0.0/8\n");
60
61    // Example 3: Token with ALPN restrictions (CATALPN)
62    println!("3. Creating token with CATALPN (HTTP/2 only)");
63    let token_with_catalpn = TokenBuilder::new()
64        .algorithm(Algorithm::HmacSha256)
65        .protected_key_id(KeyId::string("key-3"))
66        .registered_claims(
67            RegisteredClaims::new()
68                .with_issuer("example-issuer")
69                .with_expiration(now + 3600),
70        )
71        .custom_array(cat_keys::CATALPN, catalpn::http2_only())
72        .sign(key)
73        .expect("Failed to sign token");
74
75    println!("   ✓ Token created with CATALPN: h2 only\n");
76
77    // Example 4: Token with HTTP header requirements (CATH)
78    println!("4. Creating token with CATH (custom headers)");
79    let mut headers = BTreeMap::new();
80    headers.insert("X-API-Key", "secret-api-key");
81    headers.insert("X-Client-Version", "1.0");
82
83    let token_with_cath = TokenBuilder::new()
84        .algorithm(Algorithm::HmacSha256)
85        .protected_key_id(KeyId::string("key-4"))
86        .registered_claims(
87            RegisteredClaims::new()
88                .with_issuer("example-issuer")
89                .with_expiration(now + 3600),
90        )
91        .custom_cbor(cat_keys::CATH, cath::create(headers))
92        .sign(key)
93        .expect("Failed to sign token");
94
95    println!("   ✓ Token created with CATH: X-API-Key, X-Client-Version\n");
96
97    // Example 5: Token with geographic restrictions (CATGEO*)
98    println!("5. Creating token with geographic restrictions");
99    let token_with_geo = TokenBuilder::new()
100        .algorithm(Algorithm::HmacSha256)
101        .protected_key_id(KeyId::string("key-5"))
102        .registered_claims(
103            RegisteredClaims::new()
104                .with_issuer("example-issuer")
105                .with_expiration(now + 3600),
106        )
107        // Country restriction
108        .custom_array(cat_keys::CATGEOISO3166, catgeoiso3166::create(vec!["US"]))
109        // Coordinate restriction (New York City with 5km radius)
110        .custom_cbor(
111            cat_keys::CATGEOCOORD,
112            catgeocoord::with_radius(40.7128, -74.0060, 5000),
113        )
114        // Altitude restriction (0-1000 meters)
115        .custom_cbor(cat_keys::CATGEOALT, catgeoalt::range(0, 1000))
116        .sign(key)
117        .expect("Failed to sign token");
118
119    println!("   ✓ Token created with CATGEOISO3166: US");
120    println!("   ✓ Token created with CATGEOCOORD: NYC (40.7128, -74.0060) ±5km");
121    println!("   ✓ Token created with CATGEOALT: 0-1000m\n");
122
123    // Example 6: Token with TLS public key pinning (CATTPK)
124    println!("6. Creating token with CATTPK (TLS key pinning)");
125    // In a real scenario, this would be the SHA-256 hash of a certificate's public key
126    let public_key_hash = vec![
127        0x01, 0x23, 0x45, 0x67, 0x89, 0xab, 0xcd, 0xef, 0x01, 0x23, 0x45, 0x67, 0x89, 0xab, 0xcd,
128        0xef, 0x01, 0x23, 0x45, 0x67, 0x89, 0xab, 0xcd, 0xef, 0x01, 0x23, 0x45, 0x67, 0x89, 0xab,
129        0xcd, 0xef,
130    ];
131
132    let token_with_cattpk = TokenBuilder::new()
133        .algorithm(Algorithm::HmacSha256)
134        .protected_key_id(KeyId::string("key-6"))
135        .registered_claims(
136            RegisteredClaims::new()
137                .with_issuer("example-issuer")
138                .with_expiration(now + 3600),
139        )
140        .custom_cbor(cat_keys::CATTPK, cattpk::create(public_key_hash.clone()))
141        .sign(key)
142        .expect("Failed to sign token");
143
144    println!("   ✓ Token created with CATTPK: public key hash (32 bytes)\n");
145
146    // Example 7: Token with DPoP settings (CATDPOP)
147    println!("7. Creating token with CATDPOP (DPoP required)");
148    let token_with_catdpop = TokenBuilder::new()
149        .algorithm(Algorithm::HmacSha256)
150        .protected_key_id(KeyId::string("key-7"))
151        .registered_claims(
152            RegisteredClaims::new()
153                .with_issuer("example-issuer")
154                .with_expiration(now + 3600),
155        )
156        .custom_cbor(cat_keys::CATDPOP, catdpop::required())
157        .sign(key)
158        .expect("Failed to sign token");
159
160    println!("   ✓ Token created with CATDPOP: DPoP required\n");
161
162    // Example 8: Token with conditional logic (CATIF/CATIFDATA)
163    println!("8. Creating token with CATIF and CATIFDATA");
164    let mut condition = BTreeMap::new();
165    condition.insert(0, common_access_token::CborValue::Text("role".to_string()));
166    condition.insert(
167        1,
168        common_access_token::CborValue::Text("equals".to_string()),
169    );
170    condition.insert(2, common_access_token::CborValue::Text("admin".to_string()));
171
172    let mut if_data = BTreeMap::new();
173    if_data.insert(0, common_access_token::CborValue::Text("role".to_string()));
174    if_data.insert(1, common_access_token::CborValue::Text("admin".to_string()));
175
176    let token_with_catif = TokenBuilder::new()
177        .algorithm(Algorithm::HmacSha256)
178        .protected_key_id(KeyId::string("key-8"))
179        .registered_claims(
180            RegisteredClaims::new()
181                .with_issuer("example-issuer")
182                .with_expiration(now + 3600),
183        )
184        .custom_cbor(cat_keys::CATIF, catif::create(condition))
185        .custom_cbor(cat_keys::CATIFDATA, catifdata::create(if_data))
186        .sign(key)
187        .expect("Failed to sign token");
188
189    println!("   ✓ Token created with CATIF: conditional logic");
190    println!("   ✓ Token created with CATIFDATA: role=admin\n");
191
192    // Example 9: Comprehensive token with multiple CAT claims
193    println!("9. Creating comprehensive token with multiple CAT claims");
194    let comprehensive_token = TokenBuilder::new()
195        .algorithm(Algorithm::HmacSha256)
196        .protected_key_id(KeyId::string("comprehensive-key"))
197        .registered_claims(
198            RegisteredClaims::new()
199                .with_issuer("secure-service")
200                .with_subject("user-12345")
201                .with_audience("api.example.com")
202                .with_expiration(now + 7200),
203        )
204        .custom_cbor(cat_keys::CATV, catv::with_version(1))
205        .custom_cbor(cat_keys::CATPOR, catpor::create(10))
206        .custom_array(cat_keys::CATNIP, catnip::single("203.0.113.0/24"))
207        .custom_array(cat_keys::CATALPN, catalpn::create(vec!["h2", "http/1.1"]))
208        .custom_array(cat_keys::CATGEOISO3166, catgeoiso3166::create(vec!["US"]))
209        .sign(key)
210        .expect("Failed to sign token");
211
212    println!("   ✓ Comprehensive token created with:");
213    println!("     - CATV: version 1");
214    println!("     - CATPOR: 10% rejection probability");
215    println!("     - CATNIP: 203.0.113.0/24");
216    println!("     - CATALPN: h2, http/1.1");
217    println!("     - CATGEOISO3166: US");
218
219    // Verify all tokens can be encoded
220    println!("\n=== Verification ===");
221    let tokens = vec![
222        ("CATPOR", &token_with_catpor),
223        ("CATNIP", &token_with_catnip),
224        ("CATALPN", &token_with_catalpn),
225        ("CATH", &token_with_cath),
226        ("CATGEO*", &token_with_geo),
227        ("CATTPK", &token_with_cattpk),
228        ("CATDPOP", &token_with_catdpop),
229        ("CATIF", &token_with_catif),
230        ("Comprehensive", &comprehensive_token),
231    ];
232
233    for (name, token) in tokens {
234        let token_bytes = token.to_bytes().expect("Failed to encode token");
235        println!("✓ {} token encoded ({} bytes)", name, token_bytes.len());
236    }
237
238    println!("\n=== All Extended CAT Claims Examples Completed Successfully ===");
239}
Source

pub fn from_bytes(bytes: &[u8]) -> Result<Self, Error>

Decode a token from CBOR bytes

This function supports both COSE_Sign1 (tag 18) and COSE_Mac0 (tag 17) structures, as well as custom tags. It will automatically skip any tags and process the underlying CBOR array.

Examples found in repository?
examples/cat_validation.rs (line 24)
7fn main() {
8    // Create a key for signing and verification
9    let key = b"my-secret-key-for-hmac-sha256";
10    let now = current_timestamp() as i64;
11
12    // Create a token with multiple CAT-specific claims
13    let token = create_token_with_cat_claims(key, now);
14
15    // Encode token to bytes
16    let token_bytes = token.to_bytes().expect("Failed to encode token");
17    println!(
18        "Token with CAT claims encoded to {} bytes",
19        token_bytes.len()
20    );
21
22    // Decode the token
23    let decoded_token =
24        common_access_token::Token::from_bytes(&token_bytes).expect("Failed to decode token");
25
26    // Verify signature
27    decoded_token
28        .verify(key)
29        .expect("Failed to verify signature");
30
31    // Demonstrate different CAT-specific claim validations
32    validate_catu_claim(&decoded_token);
33    validate_catm_claim(&decoded_token);
34    validate_catreplay_claim(&decoded_token);
35}
More examples
Hide additional examples
examples/cat_specific_claims.rs (line 20)
7fn main() {
8    // Create a key for signing and verification
9    let key = b"my-secret-key-for-hmac-sha256";
10
11    // Create a token with CAT-specific claims
12    let token = create_token_with_cat_claims(key);
13
14    // Encode token to bytes
15    let token_bytes = token.to_bytes().expect("Failed to encode token");
16    println!("Token encoded to {} bytes", token_bytes.len());
17
18    // Decode and verify the token
19    let decoded_token =
20        common_access_token::Token::from_bytes(&token_bytes).expect("Failed to decode token");
21
22    // Verify the signature
23    decoded_token
24        .verify(key)
25        .expect("Failed to verify signature");
26
27    // Verify the claims
28    let options = VerificationOptions::new()
29        .verify_exp(true)
30        .expected_issuer("example-issuer");
31
32    decoded_token
33        .verify_claims(&options)
34        .expect("Failed to verify claims");
35
36    // Print token information
37    print_token_info(&decoded_token);
38}
examples/basic_usage.rs (line 126)
124fn verify_token(token_bytes: &[u8], key: &[u8], expected_token_type: &str) {
125    // Decode the token
126    let token = match common_access_token::Token::from_bytes(token_bytes) {
127        Ok(token) => token,
128        Err(err) => {
129            println!("Failed to decode {} token: {}", expected_token_type, err);
130            return;
131        }
132    };
133
134    // Verify the signature
135    if let Err(err) = token.verify(key) {
136        println!(
137            "Failed to verify {} token signature: {}",
138            expected_token_type, err
139        );
140        return;
141    }
142
143    // Verify the claims
144    let options = VerificationOptions::new()
145        .verify_exp(true)
146        .verify_nbf(true)
147        .expected_issuer("example-issuer")
148        .expected_audience("example-audience");
149
150    if let Err(err) = token.verify_claims(&options) {
151        println!(
152            "Failed to verify {} token claims: {}",
153            expected_token_type, err
154        );
155        return;
156    }
157
158    // Get the key ID
159    let kid = token.header.key_id().expect("No key ID in token");
160    let kid_str = match &kid {
161        KeyId::Binary(data) => format!("Binary key ID: {:?}", data),
162        KeyId::String(data) => format!("String key ID: {}", data),
163    };
164
165    println!(
166        "Successfully verified {} token ({})",
167        expected_token_type, kid_str
168    );
169
170    // Print some claims
171    if let Some(iss) = &token.claims.registered.iss {
172        println!("  Issuer: {}", iss);
173    }
174    if let Some(sub) = &token.claims.registered.sub {
175        println!("  Subject: {}", sub);
176    }
177    if let Some(exp) = token.claims.registered.exp {
178        println!(
179            "  Expires at: {} (in {} seconds)",
180            exp,
181            exp - current_timestamp()
182        );
183    }
184}
185
186/// Verify a token with a nested map claim
187fn verify_nested_map_token(token_bytes: &[u8], key: &[u8]) {
188    // Decode the token
189    let token = match common_access_token::Token::from_bytes(token_bytes) {
190        Ok(token) => token,
191        Err(err) => {
192            println!("Failed to decode nested map token: {}", err);
193            return;
194        }
195    };
196
197    // Verify the signature
198    if let Err(err) = token.verify(key) {
199        println!("Failed to verify nested map token signature: {}", err);
200        return;
201    }
202
203    // Verify the claims
204    let options = VerificationOptions::new()
205        .verify_exp(true)
206        .verify_nbf(true)
207        .expected_issuer("example-issuer")
208        .expected_audience("example-audience");
209
210    if let Err(err) = token.verify_claims(&options) {
211        println!("Failed to verify nested map token claims: {}", err);
212        return;
213    }
214
215    println!("Successfully verified nested map token");
216
217    // Check for the nested map claim
218    if let Some(CborValue::Map(map)) = token.claims.custom.get(&200) {
219        println!("  Found nested map claim with {} entries", map.len());
220
221        // Print first level entries
222        if let Some(CborValue::Text(text)) = map.get(&1) {
223            println!("  Entry 1: Text = {}", text);
224        }
225
226        if let Some(CborValue::Integer(num)) = map.get(&2) {
227            println!("  Entry 2: Integer = {}", num);
228        }
229
230        if let Some(CborValue::Bytes(bytes)) = map.get(&3) {
231            println!("  Entry 3: Bytes = {:?}", bytes);
232        }
233
234        // Check for second level map
235        if let Some(CborValue::Map(second_map)) = map.get(&4) {
236            println!("  Entry 4: Nested map with {} entries", second_map.len());
237
238            if let Some(CborValue::Text(text)) = second_map.get(&1) {
239                println!("    Nested Entry 1: Text = {}", text);
240            }
241
242            if let Some(CborValue::Integer(num)) = second_map.get(&2) {
243                println!("    Nested Entry 2: Integer = {}", num);
244            }
245        }
246    } else {
247        println!("  Nested map claim not found!");
248    }
249}
Source

pub fn verify(&self, key: &[u8]) -> Result<(), Error>

Verify the token signature

This function supports both COSE_Sign1 and COSE_Mac0 structures. It will first try to verify the signature using the COSE_Sign1 structure, and if that fails, it will try the COSE_Mac0 structure.

Examples found in repository?
examples/cat_validation.rs (line 28)
7fn main() {
8    // Create a key for signing and verification
9    let key = b"my-secret-key-for-hmac-sha256";
10    let now = current_timestamp() as i64;
11
12    // Create a token with multiple CAT-specific claims
13    let token = create_token_with_cat_claims(key, now);
14
15    // Encode token to bytes
16    let token_bytes = token.to_bytes().expect("Failed to encode token");
17    println!(
18        "Token with CAT claims encoded to {} bytes",
19        token_bytes.len()
20    );
21
22    // Decode the token
23    let decoded_token =
24        common_access_token::Token::from_bytes(&token_bytes).expect("Failed to decode token");
25
26    // Verify signature
27    decoded_token
28        .verify(key)
29        .expect("Failed to verify signature");
30
31    // Demonstrate different CAT-specific claim validations
32    validate_catu_claim(&decoded_token);
33    validate_catm_claim(&decoded_token);
34    validate_catreplay_claim(&decoded_token);
35}
More examples
Hide additional examples
examples/cat_specific_claims.rs (line 24)
7fn main() {
8    // Create a key for signing and verification
9    let key = b"my-secret-key-for-hmac-sha256";
10
11    // Create a token with CAT-specific claims
12    let token = create_token_with_cat_claims(key);
13
14    // Encode token to bytes
15    let token_bytes = token.to_bytes().expect("Failed to encode token");
16    println!("Token encoded to {} bytes", token_bytes.len());
17
18    // Decode and verify the token
19    let decoded_token =
20        common_access_token::Token::from_bytes(&token_bytes).expect("Failed to decode token");
21
22    // Verify the signature
23    decoded_token
24        .verify(key)
25        .expect("Failed to verify signature");
26
27    // Verify the claims
28    let options = VerificationOptions::new()
29        .verify_exp(true)
30        .expected_issuer("example-issuer");
31
32    decoded_token
33        .verify_claims(&options)
34        .expect("Failed to verify claims");
35
36    // Print token information
37    print_token_info(&decoded_token);
38}
examples/basic_usage.rs (line 135)
124fn verify_token(token_bytes: &[u8], key: &[u8], expected_token_type: &str) {
125    // Decode the token
126    let token = match common_access_token::Token::from_bytes(token_bytes) {
127        Ok(token) => token,
128        Err(err) => {
129            println!("Failed to decode {} token: {}", expected_token_type, err);
130            return;
131        }
132    };
133
134    // Verify the signature
135    if let Err(err) = token.verify(key) {
136        println!(
137            "Failed to verify {} token signature: {}",
138            expected_token_type, err
139        );
140        return;
141    }
142
143    // Verify the claims
144    let options = VerificationOptions::new()
145        .verify_exp(true)
146        .verify_nbf(true)
147        .expected_issuer("example-issuer")
148        .expected_audience("example-audience");
149
150    if let Err(err) = token.verify_claims(&options) {
151        println!(
152            "Failed to verify {} token claims: {}",
153            expected_token_type, err
154        );
155        return;
156    }
157
158    // Get the key ID
159    let kid = token.header.key_id().expect("No key ID in token");
160    let kid_str = match &kid {
161        KeyId::Binary(data) => format!("Binary key ID: {:?}", data),
162        KeyId::String(data) => format!("String key ID: {}", data),
163    };
164
165    println!(
166        "Successfully verified {} token ({})",
167        expected_token_type, kid_str
168    );
169
170    // Print some claims
171    if let Some(iss) = &token.claims.registered.iss {
172        println!("  Issuer: {}", iss);
173    }
174    if let Some(sub) = &token.claims.registered.sub {
175        println!("  Subject: {}", sub);
176    }
177    if let Some(exp) = token.claims.registered.exp {
178        println!(
179            "  Expires at: {} (in {} seconds)",
180            exp,
181            exp - current_timestamp()
182        );
183    }
184}
185
186/// Verify a token with a nested map claim
187fn verify_nested_map_token(token_bytes: &[u8], key: &[u8]) {
188    // Decode the token
189    let token = match common_access_token::Token::from_bytes(token_bytes) {
190        Ok(token) => token,
191        Err(err) => {
192            println!("Failed to decode nested map token: {}", err);
193            return;
194        }
195    };
196
197    // Verify the signature
198    if let Err(err) = token.verify(key) {
199        println!("Failed to verify nested map token signature: {}", err);
200        return;
201    }
202
203    // Verify the claims
204    let options = VerificationOptions::new()
205        .verify_exp(true)
206        .verify_nbf(true)
207        .expected_issuer("example-issuer")
208        .expected_audience("example-audience");
209
210    if let Err(err) = token.verify_claims(&options) {
211        println!("Failed to verify nested map token claims: {}", err);
212        return;
213    }
214
215    println!("Successfully verified nested map token");
216
217    // Check for the nested map claim
218    if let Some(CborValue::Map(map)) = token.claims.custom.get(&200) {
219        println!("  Found nested map claim with {} entries", map.len());
220
221        // Print first level entries
222        if let Some(CborValue::Text(text)) = map.get(&1) {
223            println!("  Entry 1: Text = {}", text);
224        }
225
226        if let Some(CborValue::Integer(num)) = map.get(&2) {
227            println!("  Entry 2: Integer = {}", num);
228        }
229
230        if let Some(CborValue::Bytes(bytes)) = map.get(&3) {
231            println!("  Entry 3: Bytes = {:?}", bytes);
232        }
233
234        // Check for second level map
235        if let Some(CborValue::Map(second_map)) = map.get(&4) {
236            println!("  Entry 4: Nested map with {} entries", second_map.len());
237
238            if let Some(CborValue::Text(text)) = second_map.get(&1) {
239                println!("    Nested Entry 1: Text = {}", text);
240            }
241
242            if let Some(CborValue::Integer(num)) = second_map.get(&2) {
243                println!("    Nested Entry 2: Integer = {}", num);
244            }
245        }
246    } else {
247        println!("  Nested map claim not found!");
248    }
249}
Source

pub fn verify_claims(&self, options: &VerificationOptions) -> Result<(), Error>

Verify the token claims

Examples found in repository?
examples/cat_specific_claims.rs (line 33)
7fn main() {
8    // Create a key for signing and verification
9    let key = b"my-secret-key-for-hmac-sha256";
10
11    // Create a token with CAT-specific claims
12    let token = create_token_with_cat_claims(key);
13
14    // Encode token to bytes
15    let token_bytes = token.to_bytes().expect("Failed to encode token");
16    println!("Token encoded to {} bytes", token_bytes.len());
17
18    // Decode and verify the token
19    let decoded_token =
20        common_access_token::Token::from_bytes(&token_bytes).expect("Failed to decode token");
21
22    // Verify the signature
23    decoded_token
24        .verify(key)
25        .expect("Failed to verify signature");
26
27    // Verify the claims
28    let options = VerificationOptions::new()
29        .verify_exp(true)
30        .expected_issuer("example-issuer");
31
32    decoded_token
33        .verify_claims(&options)
34        .expect("Failed to verify claims");
35
36    // Print token information
37    print_token_info(&decoded_token);
38}
More examples
Hide additional examples
examples/basic_usage.rs (line 150)
124fn verify_token(token_bytes: &[u8], key: &[u8], expected_token_type: &str) {
125    // Decode the token
126    let token = match common_access_token::Token::from_bytes(token_bytes) {
127        Ok(token) => token,
128        Err(err) => {
129            println!("Failed to decode {} token: {}", expected_token_type, err);
130            return;
131        }
132    };
133
134    // Verify the signature
135    if let Err(err) = token.verify(key) {
136        println!(
137            "Failed to verify {} token signature: {}",
138            expected_token_type, err
139        );
140        return;
141    }
142
143    // Verify the claims
144    let options = VerificationOptions::new()
145        .verify_exp(true)
146        .verify_nbf(true)
147        .expected_issuer("example-issuer")
148        .expected_audience("example-audience");
149
150    if let Err(err) = token.verify_claims(&options) {
151        println!(
152            "Failed to verify {} token claims: {}",
153            expected_token_type, err
154        );
155        return;
156    }
157
158    // Get the key ID
159    let kid = token.header.key_id().expect("No key ID in token");
160    let kid_str = match &kid {
161        KeyId::Binary(data) => format!("Binary key ID: {:?}", data),
162        KeyId::String(data) => format!("String key ID: {}", data),
163    };
164
165    println!(
166        "Successfully verified {} token ({})",
167        expected_token_type, kid_str
168    );
169
170    // Print some claims
171    if let Some(iss) = &token.claims.registered.iss {
172        println!("  Issuer: {}", iss);
173    }
174    if let Some(sub) = &token.claims.registered.sub {
175        println!("  Subject: {}", sub);
176    }
177    if let Some(exp) = token.claims.registered.exp {
178        println!(
179            "  Expires at: {} (in {} seconds)",
180            exp,
181            exp - current_timestamp()
182        );
183    }
184}
185
186/// Verify a token with a nested map claim
187fn verify_nested_map_token(token_bytes: &[u8], key: &[u8]) {
188    // Decode the token
189    let token = match common_access_token::Token::from_bytes(token_bytes) {
190        Ok(token) => token,
191        Err(err) => {
192            println!("Failed to decode nested map token: {}", err);
193            return;
194        }
195    };
196
197    // Verify the signature
198    if let Err(err) = token.verify(key) {
199        println!("Failed to verify nested map token signature: {}", err);
200        return;
201    }
202
203    // Verify the claims
204    let options = VerificationOptions::new()
205        .verify_exp(true)
206        .verify_nbf(true)
207        .expected_issuer("example-issuer")
208        .expected_audience("example-audience");
209
210    if let Err(err) = token.verify_claims(&options) {
211        println!("Failed to verify nested map token claims: {}", err);
212        return;
213    }
214
215    println!("Successfully verified nested map token");
216
217    // Check for the nested map claim
218    if let Some(CborValue::Map(map)) = token.claims.custom.get(&200) {
219        println!("  Found nested map claim with {} entries", map.len());
220
221        // Print first level entries
222        if let Some(CborValue::Text(text)) = map.get(&1) {
223            println!("  Entry 1: Text = {}", text);
224        }
225
226        if let Some(CborValue::Integer(num)) = map.get(&2) {
227            println!("  Entry 2: Integer = {}", num);
228        }
229
230        if let Some(CborValue::Bytes(bytes)) = map.get(&3) {
231            println!("  Entry 3: Bytes = {:?}", bytes);
232        }
233
234        // Check for second level map
235        if let Some(CborValue::Map(second_map)) = map.get(&4) {
236            println!("  Entry 4: Nested map with {} entries", second_map.len());
237
238            if let Some(CborValue::Text(text)) = second_map.get(&1) {
239                println!("    Nested Entry 1: Text = {}", text);
240            }
241
242            if let Some(CborValue::Integer(num)) = second_map.get(&2) {
243                println!("    Nested Entry 2: Integer = {}", num);
244            }
245        }
246    } else {
247        println!("  Nested map claim not found!");
248    }
249}
examples/cat_validation.rs (line 106)
93fn validate_catu_claim(token: &common_access_token::Token) {
94    println!("\nValidating CATU (URI) claim:");
95
96    // Define URIs to test
97    let valid_uri = "https://api.example.com/api/users.json";
98    let invalid_scheme_uri = "http://api.example.com/api/users.json";
99    let invalid_host_uri = "https://api.other-site.com/api/users.json";
100    let invalid_path_uri = "https://api.example.com/users.json";
101    let invalid_extension_uri = "https://api.example.com/api/users.xml";
102
103    // Test valid URI
104    let options = VerificationOptions::new().verify_catu(true).uri(valid_uri);
105
106    match token.verify_claims(&options) {
107        Ok(_) => println!("  VALID URI: {}", valid_uri),
108        Err(e) => println!(
109            "  ERROR: {} should be valid, but got error: {}",
110            valid_uri, e
111        ),
112    }
113
114    // Test invalid scheme
115    let invalid_scheme_options = VerificationOptions::new()
116        .verify_catu(true)
117        .uri(invalid_scheme_uri);
118
119    match token.verify_claims(&invalid_scheme_options) {
120        Ok(_) => println!(
121            "  ERROR: {} should be invalid (wrong scheme)",
122            invalid_scheme_uri
123        ),
124        Err(e) => println!(
125            "  INVALID URI (as expected): {} - Error: {}",
126            invalid_scheme_uri, e
127        ),
128    }
129
130    // Test invalid host
131    let invalid_host_options = VerificationOptions::new()
132        .verify_catu(true)
133        .uri(invalid_host_uri);
134
135    match token.verify_claims(&invalid_host_options) {
136        Ok(_) => println!(
137            "  ERROR: {} should be invalid (wrong host)",
138            invalid_host_uri
139        ),
140        Err(e) => println!(
141            "  INVALID URI (as expected): {} - Error: {}",
142            invalid_host_uri, e
143        ),
144    }
145
146    // Test invalid path
147    let invalid_path_options = VerificationOptions::new()
148        .verify_catu(true)
149        .uri(invalid_path_uri);
150
151    match token.verify_claims(&invalid_path_options) {
152        Ok(_) => println!(
153            "  ERROR: {} should be invalid (wrong path)",
154            invalid_path_uri
155        ),
156        Err(e) => println!(
157            "  INVALID URI (as expected): {} - Error: {}",
158            invalid_path_uri, e
159        ),
160    }
161
162    // Test invalid extension
163    let invalid_extension_options = VerificationOptions::new()
164        .verify_catu(true)
165        .uri(invalid_extension_uri);
166
167    match token.verify_claims(&invalid_extension_options) {
168        Ok(_) => println!(
169            "  ERROR: {} should be invalid (wrong extension)",
170            invalid_extension_uri
171        ),
172        Err(e) => println!(
173            "  INVALID URI (as expected): {} - Error: {}",
174            invalid_extension_uri, e
175        ),
176    }
177}
178
179/// Validate the CATM claim against different HTTP methods
180fn validate_catm_claim(token: &common_access_token::Token) {
181    println!("\nValidating CATM (HTTP Methods) claim:");
182
183    // Test allowed methods
184    for method in &["GET", "HEAD", "OPTIONS"] {
185        let options = VerificationOptions::new()
186            .verify_catm(true)
187            .http_method(*method);
188
189        match token.verify_claims(&options) {
190            Ok(_) => println!("  VALID METHOD: {}", method),
191            Err(e) => println!("  ERROR: {} should be valid, but got error: {}", method, e),
192        }
193    }
194
195    // Test disallowed methods
196    for method in &["POST", "PUT", "DELETE", "PATCH"] {
197        let options = VerificationOptions::new()
198            .verify_catm(true)
199            .http_method(*method);
200
201        match token.verify_claims(&options) {
202            Ok(_) => println!("  ERROR: {} should be invalid method", method),
203            Err(e) => println!("  INVALID METHOD (as expected): {} - Error: {}", method, e),
204        }
205    }
206}
207
208/// Validate the CATREPLAY claim
209fn validate_catreplay_claim(token: &common_access_token::Token) {
210    println!("\nValidating CATREPLAY claim:");
211
212    // Test with token not seen before (should pass)
213    let options_not_seen = VerificationOptions::new()
214        .verify_catreplay(true)
215        .token_seen_before(false);
216
217    match token.verify_claims(&options_not_seen) {
218        Ok(_) => println!("  VALID: Token not seen before is accepted (as expected)"),
219        Err(e) => println!(
220            "  ERROR: Token not seen before should be valid, but got error: {}",
221            e
222        ),
223    }
224
225    // Test with token seen before (should fail with replay prohibited)
226    let options_seen = VerificationOptions::new()
227        .verify_catreplay(true)
228        .token_seen_before(true);
229
230    match token.verify_claims(&options_seen) {
231        Ok(_) => println!("  ERROR: Token seen before should be rejected"),
232        Err(e) => println!(
233            "  INVALID (as expected): Token seen before is rejected - Error: {}",
234            e
235        ),
236    }
237}
Source

pub fn is_expired(&self) -> bool

Check if the token has expired

Returns true if the token has an expiration claim and the current time is at or after it. Returns false if the token has no expiration claim or if it hasn’t expired yet.

§Example
use common_access_token::{TokenBuilder, Algorithm, RegisteredClaims, current_timestamp};

let key = b"my-secret-key";
let now = current_timestamp();

// Token that expires in 1 hour
let token = TokenBuilder::new()
    .algorithm(Algorithm::HmacSha256)
    .registered_claims(RegisteredClaims::new().with_expiration(now + 3600))
    .sign(key)
    .unwrap();

assert!(!token.is_expired());
Source

pub fn expires_in(&self) -> Option<Duration>

Get the duration until token expiration

Returns Some(Duration) if the token has an expiration claim and hasn’t expired yet. Returns None if the token has no expiration claim or has already expired.

§Example
use common_access_token::{TokenBuilder, Algorithm, RegisteredClaims, current_timestamp};

let key = b"my-secret-key";
let now = current_timestamp();

let token = TokenBuilder::new()
    .algorithm(Algorithm::HmacSha256)
    .registered_claims(RegisteredClaims::new().with_expiration(now + 3600))
    .sign(key)
    .unwrap();

if let Some(duration) = token.expires_in() {
    println!("Token expires in {} seconds", duration.as_secs());
}
Source

pub fn is_valid_yet(&self) -> bool

Check if the token is valid based on the not-before (nbf) claim

Returns true if the token has no nbf claim or if the current time is at or after it. Returns false if the token has an nbf claim and the current time is before it.

§Example
use common_access_token::{TokenBuilder, Algorithm, RegisteredClaims, current_timestamp};

let key = b"my-secret-key";
let now = current_timestamp();

let token = TokenBuilder::new()
    .algorithm(Algorithm::HmacSha256)
    .registered_claims(RegisteredClaims::new().with_not_before(now))
    .sign(key)
    .unwrap();

assert!(token.is_valid_yet());
Source

pub fn issuer(&self) -> Option<&str>

Get the issuer claim value

§Example
use common_access_token::{TokenBuilder, Algorithm, RegisteredClaims};

let key = b"my-secret-key";
let token = TokenBuilder::new()
    .algorithm(Algorithm::HmacSha256)
    .registered_claims(RegisteredClaims::new().with_issuer("example-issuer"))
    .sign(key)
    .unwrap();

assert_eq!(token.issuer(), Some("example-issuer"));
Source

pub fn subject(&self) -> Option<&str>

Get the subject claim value

§Example
use common_access_token::{TokenBuilder, Algorithm, RegisteredClaims};

let key = b"my-secret-key";
let token = TokenBuilder::new()
    .algorithm(Algorithm::HmacSha256)
    .registered_claims(RegisteredClaims::new().with_subject("user-123"))
    .sign(key)
    .unwrap();

assert_eq!(token.subject(), Some("user-123"));
Source

pub fn audience(&self) -> Option<&str>

Get the audience claim value

§Example
use common_access_token::{TokenBuilder, Algorithm, RegisteredClaims};

let key = b"my-secret-key";
let token = TokenBuilder::new()
    .algorithm(Algorithm::HmacSha256)
    .registered_claims(RegisteredClaims::new().with_audience("api-service"))
    .sign(key)
    .unwrap();

assert_eq!(token.audience(), Some("api-service"));
Source

pub fn expiration(&self) -> Option<u64>

Get the expiration timestamp

Source

pub fn not_before(&self) -> Option<u64>

Get the not-before timestamp

Source

pub fn issued_at(&self) -> Option<u64>

Get the issued-at timestamp

Source

pub fn get_custom_string(&self, key: i32) -> Option<&str>

Get a custom claim as a string

Returns Some(&str) if the claim exists and is a text value, None otherwise.

§Example
use common_access_token::{TokenBuilder, Algorithm};

let key = b"my-secret-key";
let token = TokenBuilder::new()
    .algorithm(Algorithm::HmacSha256)
    .custom_string(100, "custom-value")
    .sign(key)
    .unwrap();

assert_eq!(token.get_custom_string(100), Some("custom-value"));
assert_eq!(token.get_custom_string(999), None);
Source

pub fn get_custom_int(&self, key: i32) -> Option<i64>

Get a custom claim as an integer

Returns Some(i64) if the claim exists and is an integer value, None otherwise.

§Example
use common_access_token::{TokenBuilder, Algorithm};

let key = b"my-secret-key";
let token = TokenBuilder::new()
    .algorithm(Algorithm::HmacSha256)
    .custom_int(100, 42)
    .sign(key)
    .unwrap();

assert_eq!(token.get_custom_int(100), Some(42));
assert_eq!(token.get_custom_int(999), None);
Source

pub fn get_custom_binary(&self, key: i32) -> Option<&[u8]>

Get a custom claim as binary data

Returns Some(&[u8]) if the claim exists and is a bytes value, None otherwise.

§Example
use common_access_token::{TokenBuilder, Algorithm};

let key = b"my-secret-key";
let data = vec![1, 2, 3, 4];
let token = TokenBuilder::new()
    .algorithm(Algorithm::HmacSha256)
    .custom_binary(100, data.clone())
    .sign(key)
    .unwrap();

assert_eq!(token.get_custom_binary(100), Some(data.as_slice()));
assert_eq!(token.get_custom_binary(999), None);
Source

pub fn get_custom_claim(&self, key: i32) -> Option<&CborValue>

Get a reference to a custom claim value

Returns Some(&CborValue) if the claim exists, None otherwise.

§Example
use common_access_token::{TokenBuilder, Algorithm, CborValue};

let key = b"my-secret-key";
let token = TokenBuilder::new()
    .algorithm(Algorithm::HmacSha256)
    .custom_string(100, "value")
    .sign(key)
    .unwrap();

if let Some(CborValue::Text(s)) = token.get_custom_claim(100) {
    assert_eq!(s, "value");
}
Source

pub fn has_custom_claim(&self, key: i32) -> bool

Check if a custom claim exists

§Example
use common_access_token::{TokenBuilder, Algorithm};

let key = b"my-secret-key";
let token = TokenBuilder::new()
    .algorithm(Algorithm::HmacSha256)
    .custom_string(100, "value")
    .sign(key)
    .unwrap();

assert!(token.has_custom_claim(100));
assert!(!token.has_custom_claim(999));

Trait Implementations§

Source§

impl Clone for Token

Source§

fn clone(&self) -> Token

Returns a duplicate of the value. Read more
1.0.0 · Source§

fn clone_from(&mut self, source: &Self)

Performs copy-assignment from source. Read more
Source§

impl Debug for Token

Source§

fn fmt(&self, f: &mut Formatter<'_>) -> Result

Formats the value using the given formatter. Read more

Auto Trait Implementations§

§

impl Freeze for Token

§

impl RefUnwindSafe for Token

§

impl Send for Token

§

impl Sync for Token

§

impl Unpin for Token

§

impl UnwindSafe for Token

Blanket Implementations§

Source§

impl<T> Any for T
where T: 'static + ?Sized,

Source§

fn type_id(&self) -> TypeId

Gets the TypeId of self. Read more
Source§

impl<T> Borrow<T> for T
where T: ?Sized,

Source§

fn borrow(&self) -> &T

Immutably borrows from an owned value. Read more
Source§

impl<T> BorrowMut<T> for T
where T: ?Sized,

Source§

fn borrow_mut(&mut self) -> &mut T

Mutably borrows from an owned value. Read more
Source§

impl<T> CloneToUninit for T
where T: Clone,

Source§

unsafe fn clone_to_uninit(&self, dest: *mut u8)

🔬This is a nightly-only experimental API. (clone_to_uninit)
Performs copy-assignment from self to dest. Read more
Source§

impl<T> From<T> for T

Source§

fn from(t: T) -> T

Returns the argument unchanged.

Source§

impl<T, U> Into<U> for T
where U: From<T>,

Source§

fn into(self) -> U

Calls U::from(self).

That is, this conversion is whatever the implementation of From<T> for U chooses to do.

Source§

impl<T> ToOwned for T
where T: Clone,

Source§

type Owned = T

The resulting type after obtaining ownership.
Source§

fn to_owned(&self) -> T

Creates owned data from borrowed data, usually by cloning. Read more
Source§

fn clone_into(&self, target: &mut T)

Uses borrowed data to replace owned data, usually by cloning. Read more
Source§

impl<T, U> TryFrom<U> for T
where U: Into<T>,

Source§

type Error = Infallible

The type returned in the event of a conversion error.
Source§

fn try_from(value: U) -> Result<T, <T as TryFrom<U>>::Error>

Performs the conversion.
Source§

impl<T, U> TryInto<U> for T
where U: TryFrom<T>,

Source§

type Error = <U as TryFrom<T>>::Error

The type returned in the event of a conversion error.
Source§

fn try_into(self) -> Result<U, <U as TryFrom<T>>::Error>

Performs the conversion.
Source§

impl<T> ErasedDestructor for T
where T: 'static,