this repo has no description
1use super::{Claims, Header};
2use anyhow::Result;
3use base64::Engine as _;
4use base64::engine::general_purpose::URL_SAFE_NO_PAD;
5use chrono::{Duration, Utc};
6use k256::ecdsa::{Signature, SigningKey, signature::Signer};
7use uuid;
8
9pub fn create_access_token(did: &str, key_bytes: &[u8]) -> Result<String> {
10 create_signed_token(did, "access", key_bytes, Duration::minutes(15))
11}
12
13pub fn create_refresh_token(did: &str, key_bytes: &[u8]) -> Result<String> {
14 create_signed_token(did, "refresh", key_bytes, Duration::days(7))
15}
16
17pub fn create_service_token(did: &str, aud: &str, lxm: &str, key_bytes: &[u8]) -> Result<String> {
18 let signing_key = SigningKey::from_slice(key_bytes)?;
19
20 let expiration = Utc::now()
21 .checked_add_signed(Duration::seconds(60))
22 .expect("valid timestamp")
23 .timestamp();
24
25 let claims = Claims {
26 iss: did.to_owned(),
27 sub: did.to_owned(),
28 aud: aud.to_owned(),
29 exp: expiration as usize,
30 iat: Utc::now().timestamp() as usize,
31 scope: None,
32 lxm: Some(lxm.to_string()),
33 jti: uuid::Uuid::new_v4().to_string(),
34 };
35
36 sign_claims(claims, &signing_key)
37}
38
39fn create_signed_token(
40 did: &str,
41 scope: &str,
42 key_bytes: &[u8],
43 duration: Duration,
44) -> Result<String> {
45 let signing_key = SigningKey::from_slice(key_bytes)?;
46
47 let expiration = Utc::now()
48 .checked_add_signed(duration)
49 .expect("valid timestamp")
50 .timestamp();
51
52 let claims = Claims {
53 iss: did.to_owned(),
54 sub: did.to_owned(),
55 aud: format!(
56 "did:web:{}",
57 std::env::var("PDS_HOSTNAME").unwrap_or_else(|_| "localhost".to_string())
58 ),
59 exp: expiration as usize,
60 iat: Utc::now().timestamp() as usize,
61 scope: Some(scope.to_string()),
62 lxm: None,
63 jti: uuid::Uuid::new_v4().to_string(),
64 };
65
66 sign_claims(claims, &signing_key)
67}
68
69fn sign_claims(claims: Claims, key: &SigningKey) -> Result<String> {
70 let header = Header {
71 alg: "ES256K".to_string(),
72 typ: "JWT".to_string(),
73 };
74
75 let header_json = serde_json::to_string(&header)?;
76 let claims_json = serde_json::to_string(&claims)?;
77
78 let header_b64 = URL_SAFE_NO_PAD.encode(header_json);
79 let claims_b64 = URL_SAFE_NO_PAD.encode(claims_json);
80
81 let message = format!("{}.{}", header_b64, claims_b64);
82 let signature: Signature = key.sign(message.as_bytes());
83 let signature_b64 = URL_SAFE_NO_PAD.encode(signature.to_bytes());
84
85 Ok(format!("{}.{}", message, signature_b64))
86}