-
Notifications
You must be signed in to change notification settings - Fork 3
/
Copy pathjwt.rs
113 lines (99 loc) · 3.06 KB
/
jwt.rs
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
use crate::Sign;
use anyhow::{anyhow, Result};
use getset::Getters;
use jsonwebtoken::{Algorithm, DecodingKey, Header, Validation};
use serde::de::DeserializeOwned;
use serde::Serialize;
use std::sync::Arc;
#[derive(Debug, Serialize, Getters)]
pub struct JsonWebToken<C>
where
C: Serialize,
{
#[getset(get = "pub")]
pub header: Header,
pub payload: C,
}
impl<C> JsonWebToken<C>
where
C: Serialize,
{
pub fn new(header: Header, payload: C) -> Self {
JsonWebToken { header, payload }
}
pub fn kid(mut self, kid: String) -> Self {
self.header.kid = Some(kid);
self
}
}
pub fn extract_header(jwt: &str) -> Result<(String, Algorithm)> {
let header = jsonwebtoken::decode_header(jwt)?;
if let Some(kid) = header.kid {
Ok((kid, header.alg))
} else {
Err(anyhow!("No key identifier found in the header."))
}
}
pub fn decode<T>(jwt: &str, public_key: Vec<u8>, algorithm: Algorithm) -> Result<T>
where
T: DeserializeOwned,
{
let key = DecodingKey::from_ed_der(public_key.as_slice());
Ok(jsonwebtoken::decode::<T>(jwt, &key, &Validation::new(algorithm))?.claims)
}
pub fn encode<C, S>(signer: Arc<S>, header: Header, claims: C) -> Result<String>
where
C: Serialize + Send,
S: Sign + ?Sized,
{
let kid = signer.key_id().ok_or(anyhow!("No key identifier found."))?;
let jwt = JsonWebToken::new(header, claims).kid(kid);
let message = [base64_url_encode(&jwt.header)?, base64_url_encode(&jwt.payload)?].join(".");
let proof_value = signer.sign(&message)?;
let signature = base64_url::encode(proof_value.as_slice());
let message = [message, signature].join(".");
Ok(message)
}
fn base64_url_encode<T>(value: &T) -> Result<String>
where
T: ?Sized + Serialize,
{
Ok(base64_url::encode(serde_json::to_vec(value)?.as_slice()))
}
#[cfg(test)]
mod tests {
use super::*;
use crate::{
test_utils::{MockVerifier, TestSubject},
Verify,
};
use serde_json::{json, Value};
#[tokio::test]
async fn test_encode() {
let claims = json!({
"iss": "did:example:123",
"sub": "did:example:123",
"aud": "did:example:456",
"exp": 9223372036854775807i64,
"iat": 1593436422,
"nonce": "nonce",
});
let subject = TestSubject::new("did:test:123".to_string(), "key_id".to_string()).unwrap();
let encoded = encode(Arc::new(subject), Header::new(Algorithm::EdDSA), claims).unwrap();
let verifier = MockVerifier::new();
let (kid, algorithm) = extract_header(&encoded).unwrap();
let public_key = verifier.public_key(&kid).await.unwrap();
let decoded: Value = decode(&encoded, public_key, algorithm).unwrap();
assert_eq!(
decoded,
json!({
"iss": "did:example:123",
"sub": "did:example:123",
"aud": "did:example:456",
"exp": 9223372036854775807i64,
"iat": 1593436422,
"nonce": "nonce",
})
)
}
}