ts_token/
issuer.rs

1//! JSON web token issuer
2
3use std::time::UNIX_EPOCH;
4
5use ts_crypto::any::{SigningKey, VerifyingKey};
6
7use crate::{
8    Algorithm, Curve, JsonWebKey, JsonWebToken,
9    jwt::{Claims, Header, TokenType},
10};
11
12/// A token issuer
13pub struct TokenIssuer {
14    /// The JSON web key for the signing key.
15    jwk: JsonWebKey,
16    /// The signing key.
17    key: SigningKey,
18}
19
20impl TokenIssuer {
21    /// Issue a JSON web token using this key.
22    ///
23    /// ## Panics
24    /// * If system time is before `UNIX` epoch
25    pub fn issue_token(&self, subject: String, token_type: TokenType) -> JsonWebToken {
26        let valid_for = token_type.valid_for();
27
28        let now_seconds = UNIX_EPOCH
29            .elapsed()
30            .expect("system time should be ahead of unix epoch")
31            .as_secs();
32
33        let claims = Claims {
34            exp: now_seconds + valid_for.as_secs(),
35            iat: now_seconds,
36            sub: subject,
37            typ: token_type,
38        };
39
40        let header = Header {
41            alg: self.jwk.alg.to_string(),
42            typ: "JWT".to_string(),
43            kid: self.jwk.kid.clone(),
44        };
45
46        let message = JsonWebToken::create_message(&header, &claims);
47
48        let signature = match &self.key {
49            SigningKey::Ecdsa(key) => match self.jwk.alg {
50                Algorithm::ES256 => key.sign_sha256(&message),
51                Algorithm::ES384 => key.sign_sha384(&message),
52                Algorithm::ES512 => key.sign_sha512(&message),
53                _ => panic!("ECDSA key with non-ECDSA algorithm"),
54            },
55            SigningKey::EdDsa(key) => match (self.jwk.alg, self.jwk.crv) {
56                (Algorithm::Ed448, _)
57                | (Algorithm::Ed25519, _)
58                | (Algorithm::EdDSA, Some(Curve::Ed448))
59                | (Algorithm::EdDSA, Some(Curve::Ed25519)) => key.sign(&message),
60                _ => panic!("EdDSA key with non-EdDSA curve/algorithm"),
61            },
62            SigningKey::Rsa(key) => match self.jwk.alg {
63                Algorithm::RS256 => key.sign_rs256(&message),
64                Algorithm::RS384 => key.sign_rs384(&message),
65                Algorithm::RS512 => key.sign_rs512(&message),
66                Algorithm::PS256 => key.sign_ps256(&message),
67                Algorithm::PS384 => key.sign_ps384(&message),
68                Algorithm::PS512 => key.sign_ps512(&message),
69                _ => panic!("RSA key with non-RSA algorithm"),
70            },
71        };
72
73        JsonWebToken {
74            header,
75            claims,
76            signature,
77        }
78    }
79
80    /// The issuer's JSON web key
81    pub fn jwk(&self) -> &JsonWebKey {
82        &self.jwk
83    }
84
85    /// Create an issuer from a key.
86    pub fn from_key(key: SigningKey) -> Option<Self> {
87        let verifier = match key {
88            SigningKey::Ecdsa(ref key) => VerifyingKey::Ecdsa(key.verifying_key()),
89            SigningKey::EdDsa(ref key) => VerifyingKey::EdDsa(key.verifying_key()),
90            SigningKey::Rsa(ref key) => VerifyingKey::Rsa(key.verifying_key()),
91        };
92        let jwk = JsonWebKey::from_key(&verifier)?;
93
94        Some(Self { jwk, key })
95    }
96}