AtAuth
at main 113 lines 4.1 kB view raw
1//! Basic token verification example 2//! 3//! This example demonstrates how to verify tokens from an AT Protocol auth gateway. 4//! 5//! Run with: cargo run --example basic_verification 6 7use atauth::{AuthError, TokenPayload, TokenVerifier}; 8use std::collections::HashMap; 9 10fn main() { 11 // Your HMAC secret (shared with the auth gateway) 12 // Must be at least 32 bytes (256 bits) for security 13 let secret = b"your-super-secret-key-at-least-32-bytes-long!"; 14 15 // Create a verifier 16 let verifier = TokenVerifier::new(secret) 17 .expect("Secret must be at least 32 bytes") 18 .with_clock_skew(60) // Allow 60 seconds clock skew 19 .with_format_validation(true); // Validate DID/handle formats 20 21 // Create a test token (in real use, this comes from the client) 22 let test_payload = create_test_payload(); 23 let token = verifier.sign(&test_payload).expect("Failed to sign"); 24 25 println!("Generated token: {}", token); 26 println!(); 27 28 // Verify the token 29 match verifier.verify(&token) { 30 Ok(payload) => { 31 println!("[OK] Token verified successfully!"); 32 println!(); 33 println!("User Information:"); 34 println!(" DID: {}", payload.did); 35 println!(" Handle: {}", payload.handle); 36 println!(" User ID: {:?}", payload.user_id); 37 println!(" App ID: {:?}", payload.app_id); 38 println!(); 39 println!("Token Timing:"); 40 println!(" Issued: {} seconds ago", payload.age_seconds()); 41 println!(" Expires in: {} seconds", payload.remaining_seconds()); 42 println!(" Is expired: {}", payload.is_expired()); 43 } 44 Err(e) => { 45 println!("[FAIL] Token verification failed!"); 46 println!(" Error: {}", e); 47 println!(" HTTP Status: {}", e.http_status_code()); 48 } 49 } 50 51 println!(); 52 println!("--- Testing Error Cases ---"); 53 println!(); 54 55 // Test invalid signature 56 let wrong_verifier = TokenVerifier::new(b"wrong-secret-that-is-32-bytes-long!") 57 .expect("Secret must be at least 32 bytes"); 58 match wrong_verifier.verify(&token) { 59 Ok(_) => println!("[FAIL] Should have failed!"), 60 Err(AuthError::InvalidSignature) => { 61 println!("[OK] Correctly rejected invalid signature"); 62 } 63 Err(e) => println!("[WARN] Unexpected error: {}", e), 64 } 65 66 // Test invalid format 67 match verifier.verify("not-a-valid-token") { 68 Ok(_) => println!("[FAIL] Should have failed!"), 69 Err(AuthError::InvalidFormat(_)) => { 70 println!("[OK] Correctly rejected invalid format"); 71 } 72 Err(e) => println!("[WARN] Unexpected error: {}", e), 73 } 74 75 // Test expired token 76 let expired_payload = create_expired_payload(); 77 let expired_token = verifier.sign(&expired_payload).expect("Failed to sign"); 78 match verifier.verify(&expired_token) { 79 Ok(_) => println!("[FAIL] Should have failed!"), 80 Err(AuthError::Expired) => { 81 println!("[OK] Correctly rejected expired token"); 82 } 83 Err(e) => println!("[WARN] Unexpected error: {}", e), 84 } 85} 86 87fn create_test_payload() -> TokenPayload { 88 let now = chrono::Utc::now().timestamp(); 89 TokenPayload { 90 did: "did:plc:z72i7hdynmk6r22z27h6tvur".to_string(), 91 handle: "alice.bsky.social".to_string(), 92 user_id: Some(42), 93 app_id: Some("example-app".to_string()), 94 iat: now, 95 exp: now + 3600, // 1 hour from now 96 nonce: "random-nonce-12345".to_string(), 97 extra: HashMap::new(), 98 } 99} 100 101fn create_expired_payload() -> TokenPayload { 102 let now = chrono::Utc::now().timestamp(); 103 TokenPayload { 104 did: "did:plc:expired".to_string(), 105 handle: "expired.bsky.social".to_string(), 106 user_id: None, 107 app_id: None, 108 iat: now - 7200, // 2 hours ago 109 exp: now - 3600, // 1 hour ago (expired) 110 nonce: "expired-nonce".to_string(), 111 extra: HashMap::new(), 112 } 113}