1use std::collections::BTreeMap;
4
5use serde::{Deserialize, Serialize};
6
7#[derive(Clone, Debug, Default, PartialEq, Serialize, Deserialize)]
10pub struct Claims {
11 #[serde(flatten)]
12 pub registered: RegisteredClaims,
13 #[serde(flatten)]
14 pub private: BTreeMap<String, serde_json::Value>,
15}
16
17impl Claims {
18 pub fn new(registered: RegisteredClaims) -> Self {
19 Claims {
20 registered,
21 private: BTreeMap::new(),
22 }
23 }
24}
25
26pub type SecondsSinceEpoch = u64;
27
28#[derive(Clone, Debug, Default, PartialEq, Serialize, Deserialize)]
31pub struct RegisteredClaims {
32 #[serde(rename = "iss", skip_serializing_if = "Option::is_none")]
33 pub issuer: Option<String>,
34
35 #[serde(rename = "sub", skip_serializing_if = "Option::is_none")]
36 pub subject: Option<String>,
37
38 #[serde(rename = "aud", skip_serializing_if = "Option::is_none")]
39 pub audience: Option<String>,
40
41 #[serde(rename = "exp", skip_serializing_if = "Option::is_none")]
42 pub expiration: Option<SecondsSinceEpoch>,
43
44 #[serde(rename = "nbf", skip_serializing_if = "Option::is_none")]
45 pub not_before: Option<SecondsSinceEpoch>,
46
47 #[serde(rename = "iat", skip_serializing_if = "Option::is_none")]
48 pub issued_at: Option<SecondsSinceEpoch>,
49
50 #[serde(rename = "jti", skip_serializing_if = "Option::is_none")]
51 pub json_web_token_id: Option<String>,
52}
53
54#[cfg(test)]
55mod tests {
56 use crate::claims::Claims;
57 use crate::error::Error;
58 use crate::{FromBase64, ToBase64};
59 use serde_json::Value;
60 use std::default::Default;
61
62 const ENCODED_PAYLOAD: &str =
64 "eyJpc3MiOiJtaWtreWFuZy5jb20iLCJleHAiOjEzMDIzMTkxMDAsImN1c3RvbV9jbGFpbSI6dHJ1ZX0K";
65
66 #[test]
67 fn registered_claims() -> Result<(), Error> {
68 let claims = Claims::from_base64(ENCODED_PAYLOAD)?;
69
70 assert_eq!(claims.registered.issuer.unwrap(), "mikkyang.com");
71 assert_eq!(claims.registered.expiration.unwrap(), 1302319100);
72 Ok(())
73 }
74
75 #[test]
76 fn private_claims() -> Result<(), Error> {
77 let claims = Claims::from_base64(ENCODED_PAYLOAD)?;
78
79 assert_eq!(claims.private["custom_claim"], Value::Bool(true));
80 Ok(())
81 }
82
83 #[test]
84 fn roundtrip() -> Result<(), Error> {
85 let mut claims: Claims = Default::default();
86 claims.registered.issuer = Some("mikkyang.com".into());
87 claims.registered.expiration = Some(1302319100);
88 let enc = claims.to_base64()?;
89 assert_eq!(claims, Claims::from_base64(&*enc)?);
90 Ok(())
91 }
92}