AtAuth
1//! Session store example
2//!
3//! This example demonstrates how to use the session management system
4//! with SQLite backend.
5//!
6//! Run with: cargo run --example with_session_store --features session-sqlite
7
8use atauth::session::{SessionManager, SqliteSessionStore};
9use atauth::{TokenPayload, TokenVerifier};
10use std::collections::HashMap;
11
12fn main() -> Result<(), Box<dyn std::error::Error>> {
13 // Setup - secret must be at least 32 bytes (256 bits)
14 let secret = b"your-super-secret-key-at-least-32-bytes-long!";
15 let verifier = TokenVerifier::new(secret)?;
16
17 // Create an in-memory session store (use file path for persistence)
18 let session_store = SqliteSessionStore::in_memory()?;
19
20 // Create session manager with auto-extend enabled
21 let sessions = SessionManager::new(session_store)
22 .with_default_duration(86400) // 24 hours
23 .with_auto_extend(true, 3600); // Extend by 1 hour on each access
24
25 println!("=== Session Management Example ===\n");
26
27 // Simulate user login
28 println!("1. User Login");
29 println!(" Verifying token...");
30
31 let test_payload = create_test_payload();
32 let token = verifier.sign(&test_payload)?;
33
34 match verifier.verify(&token) {
35 Ok(payload) => {
36 println!(" [OK] Token verified for: {}", payload.handle);
37
38 // Create session
39 let session = sessions.create_session(&payload, token.clone())?;
40 println!(" [OK] Session created");
41 println!(" Token: {}...", &session.token[..20]);
42 println!(" Expires in: {} seconds", session.remaining_seconds());
43 }
44 Err(e) => {
45 println!(" [FAIL] Verification failed: {}", e);
46 return Ok(());
47 }
48 }
49
50 println!();
51 println!("2. Subsequent Request");
52 println!(" Validating session...");
53
54 // Simulate subsequent request with session token
55 match sessions.validate(&token) {
56 Ok(session) => {
57 println!(" [OK] Session valid for: {}", session.handle);
58 println!(" DID: {}", session.did);
59 println!(" User ID: {:?}", session.user_id);
60 }
61 Err(e) => {
62 println!(" [FAIL] Session invalid: {}", e);
63 }
64 }
65
66 println!();
67 println!("3. Get All User Sessions");
68
69 let user_sessions = sessions.get_user_sessions(&test_payload.did)?;
70 println!(
71 " Found {} session(s) for {}",
72 user_sessions.len(),
73 test_payload.did
74 );
75
76 println!();
77 println!("4. Create Another Session (same user, different device)");
78
79 // Create another session for same user
80 let second_token = verifier.sign(&test_payload)?;
81 sessions.create_session(&test_payload, second_token)?;
82 println!(" [OK] Second session created");
83
84 let user_sessions = sessions.get_user_sessions(&test_payload.did)?;
85 println!(" Now has {} sessions", user_sessions.len());
86
87 println!();
88 println!("5. Logout (invalidate first session)");
89 sessions.invalidate(&token)?;
90 println!(" [OK] First session invalidated");
91
92 let user_sessions = sessions.get_user_sessions(&test_payload.did)?;
93 println!(" Remaining sessions: {}", user_sessions.len());
94
95 println!();
96 println!("6. Logout All Devices");
97 let deleted = sessions.invalidate_all_for_did(&test_payload.did)?;
98 println!(" [OK] Deleted {} session(s)", deleted);
99
100 println!();
101 println!("7. Session Cleanup");
102 // In production, run this periodically (e.g., every hour)
103 let cleaned = sessions.cleanup()?;
104 println!(" Cleaned up {} expired session(s)", cleaned);
105
106 println!();
107 println!("=== Example Complete ===");
108
109 Ok(())
110}
111
112fn create_test_payload() -> TokenPayload {
113 let now = chrono::Utc::now().timestamp();
114 TokenPayload {
115 did: "did:plc:testuser123".to_string(),
116 handle: "testuser.bsky.social".to_string(),
117 user_id: Some(1),
118 app_id: Some("session-example".to_string()),
119 iat: now,
120 exp: now + 3600,
121 nonce: format!("nonce-{}", now),
122 extra: HashMap::new(),
123 }
124}