basic_usage/
basic_usage.rs

1use common_access_token::{
2    current_timestamp, Algorithm, CborValue, KeyId, RegisteredClaims, TokenBuilder,
3    VerificationOptions,
4};
5use std::collections::BTreeMap;
6
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}
39
40/// Create a token with a string key ID
41fn create_token_with_string_kid(key: &[u8]) -> common_access_token::Token {
42    let now = current_timestamp();
43
44    // Create a token with string key ID
45    TokenBuilder::new()
46        .algorithm(Algorithm::HmacSha256)
47        .protected_key_id(KeyId::string("string-key-example"))
48        .registered_claims(
49            RegisteredClaims::new()
50                .with_issuer("example-issuer")
51                .with_subject("example-subject")
52                .with_audience("example-audience")
53                .with_expiration(now + 3600) // 1 hour from now
54                .with_not_before(now)
55                .with_issued_at(now)
56                .with_cti(b"token-id-1234".to_vec()),
57        )
58        .custom_string(100, "custom-string-value")
59        .custom_binary(101, b"custom-binary-value".to_vec())
60        .custom_int(102, 12345)
61        .sign(key)
62        .expect("Failed to sign token")
63}
64
65/// Create a token with a binary key ID
66fn create_token_with_binary_kid(key: &[u8]) -> common_access_token::Token {
67    let now = current_timestamp();
68    let binary_kid = vec![0x01, 0x02, 0x03, 0x04, 0x05];
69
70    // Create a token with binary key ID
71    TokenBuilder::new()
72        .algorithm(Algorithm::HmacSha256)
73        .protected_key_id(KeyId::binary(binary_kid))
74        .registered_claims(
75            RegisteredClaims::new()
76                .with_issuer("example-issuer")
77                .with_subject("example-subject")
78                .with_audience("example-audience")
79                .with_expiration(now + 3600) // 1 hour from now
80                .with_not_before(now)
81                .with_issued_at(now),
82        )
83        .sign(key)
84        .expect("Failed to sign token")
85}
86
87/// Create a token with a nested map claim
88fn create_token_with_nested_map(key: &[u8]) -> common_access_token::Token {
89    let now = current_timestamp();
90
91    // Create a nested map for the token
92    let mut nested_map = BTreeMap::new();
93    nested_map.insert(1, CborValue::Text("nested-text-value".to_string()));
94    nested_map.insert(2, CborValue::Integer(42));
95    nested_map.insert(3, CborValue::Bytes(vec![1, 2, 3, 4, 5]));
96
97    // Create a second level nested map
98    let mut second_level_map = BTreeMap::new();
99    second_level_map.insert(1, CborValue::Text("second-level-text".to_string()));
100    second_level_map.insert(2, CborValue::Integer(99));
101
102    // Add the second level map to the first level
103    nested_map.insert(4, CborValue::Map(second_level_map));
104
105    // Create a token with a nested map claim
106    TokenBuilder::new()
107        .algorithm(Algorithm::HmacSha256)
108        .protected_key_id(KeyId::string("nested-map-example"))
109        .registered_claims(
110            RegisteredClaims::new()
111                .with_issuer("example-issuer")
112                .with_subject("example-subject")
113                .with_audience("example-audience")
114                .with_expiration(now + 3600) // 1 hour from now
115                .with_not_before(now)
116                .with_issued_at(now),
117        )
118        .custom_map(200, nested_map)
119        .sign(key)
120        .expect("Failed to sign token")
121}
122
123/// Verify a token
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}