import gleam/dynamic/decode.{type Decoder} import gleam/json.{type Json} import ywt/internal/core /// JWT signing algorithms combining cryptographic primitives with hash functions. /// /// Each algorithm represents a complete signing scheme including the cryptographic /// method (HMAC, ECDSA, RSA) and hash function. The choice affects security, /// performance, and compatibility with other JWT implementations. /// /// If you are unsure, choose ES384 as a secure, modern and fast default. /// /// ## Usage Examples /// ```gleam /// // For simple applications with shared secrets /// let hmac_alg = hs256 /// /// // For distributed systems with public key infrastructure /// let ecdsa_alg = es256 /// /// // The current recommendation for high-security systems /// let recommended_alg = es384 /// /// // For maximum compatibility with existing systems /// let rsa_alg = rs256 /// ``` pub opaque type Algorithm { Hs256 Hs384 Hs512 Es256 Es384 Es512 Rs256 Rs384 Rs512 Ps256 Ps384 Ps512 } /// HMAC with SHA-256 - symmetric, 256-bit security, most common for simple applications. pub const hs256 = Hs256 /// HMAC with SHA-384 - symmetric, 384-bit security, higher security margin. pub const hs384 = Hs384 /// HMAC with SHA-512 - symmetric, 512-bit security, maximum HMAC strength. pub const hs512 = Hs512 /// ECDSA with P-256 curve and SHA-256 - asymmetric, efficient, modern standard. pub const es256 = Es256 /// ECDSA with P-384 curve and SHA-384 - asymmetric, high security, enterprise grade. pub const es384 = Es384 /// ECDSA with P-521 curve and SHA-512 - asymmetric, maximum security, future-proof. pub const es512 = Es512 /// RSA PKCS#1 v1.5 with SHA-256 - asymmetric, compatible, traditional choice. pub const rs256 = Rs256 /// RSA PKCS#1 v1.5 with SHA-384 - asymmetric, compatible, higher security. pub const rs384 = Rs384 /// RSA PKCS#1 v1.5 with SHA-512 - asymmetric, compatible, maximum hash strength. pub const rs512 = Rs512 /// RSA PSS with SHA-256 - asymmetric, modern, stronger security proofs. pub const ps256 = Ps256 /// RSA PSS with SHA-384 - asymmetric, modern, high security. pub const ps384 = Ps384 /// RSA PSS with SHA-512 - asymmetric, modern, maximum security. pub const ps512 = Ps512 // -- INTERNALS --------------------------------------------------------------- @internal pub fn decoder() -> Decoder(Algorithm) { use variant <- decode.then(decode.string) case variant { "HS256" -> decode.success(Hs256) "HS384" -> decode.success(Hs384) "HS512" -> decode.success(Hs512) "ES256" -> decode.success(Es256) "ES384" -> decode.success(Es384) "ES512" -> decode.success(Es512) "RS256" -> decode.success(Rs256) "RS384" -> decode.success(Rs384) "RS512" -> decode.success(Rs512) "PS256" -> decode.success(Ps256) "PS384" -> decode.success(Ps384) "PS512" -> decode.success(Ps512) _ -> decode.failure(Hs256, "alg") } } @internal pub fn to_json(alg: Algorithm) -> Json { case alg { Hs256 -> json.string("HS256") Hs384 -> json.string("HS384") Hs512 -> json.string("HS512") Es256 -> json.string("ES256") Es384 -> json.string("ES384") Es512 -> json.string("ES512") Rs256 -> json.string("RS256") Rs384 -> json.string("RS384") Rs512 -> json.string("RS512") Ps256 -> json.string("PS256") Ps384 -> json.string("PS384") Ps512 -> json.string("PS512") } } @internal pub fn digest_type(alg: Algorithm) -> core.DigestType { case alg { Hs256 | Es256 | Rs256 | Ps256 -> core.Sha256 Hs384 | Es384 | Rs384 | Ps384 -> core.Sha384 Hs512 | Es512 | Rs512 | Ps512 -> core.Sha512 } } @internal pub fn padding(alg: Algorithm) -> Result(core.Padding, Nil) { case alg { Rs256 | Rs384 | Rs512 -> Ok(core.RsaPkcs1Padding) Ps256 | Ps384 | Ps512 -> Ok(core.RsaPkcs1PssPadding) _ -> Error(Nil) } } @internal pub fn generate_key( alg: Algorithm, generate_hmac: fn(core.DigestType) -> result, generate_ecdsa: fn(core.NamedCurve, core.DigestType) -> result, generate_rsa: fn(core.DigestType, Int, core.Padding) -> result, ) -> result { case alg { Es256 -> generate_ecdsa(core.Secp256r1, core.Sha256) Es384 -> generate_ecdsa(core.Secp384r1, core.Sha384) Es512 -> generate_ecdsa(core.Secp521r1, core.Sha512) Hs256 -> generate_hmac(core.Sha256) Hs384 -> generate_hmac(core.Sha384) Hs512 -> generate_hmac(core.Sha512) Ps256 -> generate_rsa(core.Sha256, 4096, core.RsaPkcs1PssPadding) Ps384 -> generate_rsa(core.Sha384, 4096, core.RsaPkcs1PssPadding) Ps512 -> generate_rsa(core.Sha512, 4096, core.RsaPkcs1PssPadding) Rs256 -> generate_rsa(core.Sha256, 4096, core.RsaPkcs1Padding) Rs384 -> generate_rsa(core.Sha384, 4096, core.RsaPkcs1Padding) Rs512 -> generate_rsa(core.Sha512, 4096, core.RsaPkcs1Padding) } }