ts-token 0.8.0

JSON web token library for my projects
Documentation
//! A JSON web key <https://www.iana.org/assignments/jose/jose.xhtml> used to verify signed JSON web tokens.

use base64ct::{Base64UrlUnpadded, Encoding};
use serde::{Deserialize, Serialize};
use ts_crypto::{EdwardsVerifyingKey, EllipticVerifyingKey, VerifyingKey};

/// A JSON web key <https://www.iana.org/assignments/jose/jose.xhtml> used to verify signed JSON web tokens.
#[derive(Clone, Debug, Deserialize, Serialize)]
pub struct JsonWebKey {
    /// The ID of this key.
    pub kid: String,
    /// The usage of this key. Should be `sig`.
    pub r#use: String,
    /// The algorithm this key uses.
    pub alg: String,
    /// The curve ID for elliptic keys.
    #[serde(skip_serializing_if = "Option::is_none")]
    pub crv: Option<String>,
    /// The type of the key and associated parameters.
    #[serde(flatten)]
    pub kty: KeyType,
}

/// The parameters for the given key type <https://www.iana.org/assignments/jose/jose.xhtml#web-key-types>
#[derive(Clone, Debug, Deserialize, Serialize)]
#[serde(tag = "kty")]
pub enum KeyType {
    /// <https://www.rfc-editor.org/rfc/rfc7518.html#section-6.2.1>
    #[allow(missing_docs)]
    #[serde(rename = "EC")]
    Ec { x: String, y: String },

    /// <https://www.rfc-editor.org/rfc/rfc7518.html#section-6.3>
    #[allow(missing_docs)]
    #[serde(rename = "RSA")]
    Rsa { n: String, e: String },

    /// <https://www.rfc-editor.org/rfc/rfc8037.html#section-2>
    #[allow(missing_docs)]
    #[serde(rename = "OKP")]
    Okp { x: String },
}

impl From<&VerifyingKey> for JsonWebKey {
    fn from(key: &VerifyingKey) -> Self {
        let (alg, crv) = match &key {
            VerifyingKey::Rsa(key) => match key.modulus().len() {
                value if value >= 512 => ("PS512", None),
                value if value >= 384 => ("PS384", None),
                _ => ("PS256", None),
            },
            VerifyingKey::Elliptic(key) => match key {
                EllipticVerifyingKey::Prime256(_) => ("ES256", Some("P-256")),
                EllipticVerifyingKey::Prime384(_) => ("ES384", Some("P-384")),
                EllipticVerifyingKey::Prime521(_) => ("ES512", Some("P-521")),
            },
            VerifyingKey::Edwards(key) => match key {
                EdwardsVerifyingKey::Ed25519(_) => ("Ed25519", Some("Ed25519")),
                EdwardsVerifyingKey::Ed448(_) => ("Ed448", Some("Ed448")),
            },
        };

        let kty = match &key {
            VerifyingKey::Rsa(key) => KeyType::Rsa {
                n: Base64UrlUnpadded::encode_string(&key.modulus()),
                e: Base64UrlUnpadded::encode_string(&key.exponent()),
            },
            VerifyingKey::Elliptic(key) => KeyType::Ec {
                x: Base64UrlUnpadded::encode_string(&key.x()),
                y: Base64UrlUnpadded::encode_string(&key.y()),
            },
            VerifyingKey::Edwards(key) => KeyType::Okp {
                x: Base64UrlUnpadded::encode_string(&key.raw_key()),
            },
        };

        Self {
            kid: Base64UrlUnpadded::encode_string(&key.key_id()),
            r#use: "sig".to_string(),
            alg: alg.to_string(),
            crv: crv.map(str::to_string),
            kty,
        }
    }
}