1use crate::{Result, X402Error};
4use jsonwebtoken::{Algorithm, Header};
5
6#[derive(Debug, serde::Serialize)]
8struct Claims {
9 iss: String,
10 sub: String,
11 aud: String,
12 iat: u64,
13 exp: u64,
14 uri: String,
15}
16
17#[derive(Debug, Clone)]
19pub struct JwtOptions {
20 pub key_id: String,
21 pub key_secret: String,
22 pub request_method: String,
23 pub request_host: String,
24 pub request_path: String,
25}
26
27impl JwtOptions {
28 pub fn new(
30 key_id: impl Into<String>,
31 key_secret: impl Into<String>,
32 request_method: impl Into<String>,
33 request_host: impl Into<String>,
34 request_path: impl Into<String>,
35 ) -> Self {
36 Self {
37 key_id: key_id.into(),
38 key_secret: key_secret.into(),
39 request_method: request_method.into(),
40 request_host: request_host.into(),
41 request_path: request_path.into(),
42 }
43 }
44}
45
46pub fn generate_jwt(options: JwtOptions) -> Result<String> {
48 let request_host = options.request_host.trim_start_matches("https://");
50
51 let now = chrono::Utc::now().timestamp() as u64;
52 let exp = now + 300; let claims = Claims {
55 iss: options.key_id.clone(),
56 sub: options.key_id,
57 aud: request_host.to_string(),
58 iat: now,
59 exp,
60 uri: options.request_path,
61 };
62
63 let header = Header::new(Algorithm::HS256);
64 let key = jsonwebtoken::EncodingKey::from_secret(options.key_secret.as_bytes());
65 let token = jsonwebtoken::encode(&header, &claims, &key)
66 .map_err(|e| X402Error::config(format!("JWT encoding failed: {}", e)))?;
67
68 Ok(token)
69}
70
71pub fn create_auth_header(
73 api_key_id: &str,
74 api_key_secret: &str,
75 request_host: &str,
76 request_path: &str,
77) -> Result<String> {
78 let options = JwtOptions::new(
79 api_key_id,
80 api_key_secret,
81 "POST", request_host,
83 request_path,
84 );
85
86 let token = generate_jwt(options)?;
87 Ok(format!("Bearer {}", token))
88}
89
90pub fn create_auth_header_with_method(
92 api_key_id: &str,
93 api_key_secret: &str,
94 request_method: &str,
95 request_host: &str,
96 request_path: &str,
97) -> Result<String> {
98 let options = JwtOptions::new(
99 api_key_id,
100 api_key_secret,
101 request_method,
102 request_host,
103 request_path,
104 );
105
106 let token = generate_jwt(options)?;
107 Ok(format!("Bearer {}", token))
108}