bybit_rust_api/ws/auth.rs
1//! WebSocket authentication for Bybit V5 private channels.
2//!
3//! Authentication is required for private WebSocket topics (position, execution,
4//! order, wallet). The process:
5//! 1. Generate an `expires` timestamp (current ms + 10 seconds)
6//! 2. Sign the expires value with HMAC-SHA256 using the API secret
7//! 3. Send `{"op": "auth", "args": [api_key, expires, signature]}`
8
9use crate::utils;
10
11/// Generate WebSocket authentication parameters.
12///
13/// Returns `(expires, signature)` for use in the auth request.
14///
15/// # Arguments
16/// * `secret` - Your Bybit API secret
17///
18/// # Example
19/// ```ignore
20/// let (expires, sig) = generate_auth_params("my_secret");
21/// let auth_msg = WsRequest::auth("my_key", expires, &sig);
22/// ```
23pub fn generate_auth_params(secret: &str) -> (u64, String) {
24 let expires = utils::millis() as u64 + 10_000; // 10 seconds from now
25 let expires_str = expires.to_string();
26 let signature = utils::sign(secret, &expires_str);
27 (expires, signature)
28}
29
30#[cfg(test)]
31mod tests {
32 use super::*;
33
34 #[test]
35 fn test_generate_auth_params() {
36 let (expires, sig) = generate_auth_params("test_secret");
37 assert!(expires > 0);
38 assert!(!sig.is_empty());
39 assert_eq!(sig.len(), 64); // SHA-256 hex is 64 chars
40 }
41
42 #[test]
43 fn test_auth_params_deterministic_at_same_time() {
44 // Same secret should produce different signatures at different times
45 let (e1, s1) = generate_auth_params("secret");
46 std::thread::sleep(std::time::Duration::from_millis(10));
47 let (e2, s2) = generate_auth_params("secret");
48 // expires should differ
49 assert!(e2 > e1);
50 // signatures should differ because expires differs
51 assert_ne!(s1, s2);
52 }
53}