1use jsonwebtoken::{DecodingKey, EncodingKey};
2use openssl::ec::{EcGroup, EcKey};
3use openssl::nid::Nid;
4use openssl::pkey::PKey;
5use spacetimedb_paths::cli::{PrivKeyPath, PubKeyPath};
6
7use crate::config::CertificateAuthority;
8
9pub use spacetimedb_auth::identity;
10pub mod token_validation;
11
12#[derive(Clone)]
14pub struct JwtKeys {
15 pub public: DecodingKey,
16 pub public_pem: Box<[u8]>,
17 pub private: EncodingKey,
18 pub kid: Option<String>,
19}
20
21impl JwtKeys {
22 pub fn new(public_pem: impl Into<Box<[u8]>>, private_pem: &[u8]) -> anyhow::Result<Self> {
27 let public_pem = public_pem.into();
28 let public = DecodingKey::from_ec_pem(&public_pem)?;
29 let private = EncodingKey::from_ec_pem(private_pem)?;
30
31 Ok(Self {
32 public,
33 private,
34 public_pem,
35 kid: None,
36 })
37 }
38
39 pub fn generate() -> anyhow::Result<Self> {
40 let keypair = EcKeyPair::generate()?;
41 keypair.try_into()
42 }
43}
44
45pub fn get_or_create_keys(certs: &CertificateAuthority) -> anyhow::Result<JwtKeys> {
48 let public_key_path = &certs.jwt_pub_key_path;
49 let private_key_path = &certs.jwt_priv_key_path;
50
51 let public_key_bytes = public_key_path.read().ok();
52 let private_key_bytes = private_key_path.read().ok();
53
54 let key_pair = match (public_key_bytes, private_key_bytes) {
56 (Some(pub_), Some(priv_)) => EcKeyPair::new(pub_, priv_),
57 (None, None) => {
58 let keys = EcKeyPair::generate()?;
59 keys.write_to_files(public_key_path, private_key_path)?;
60 keys
61 }
62 (None, Some(_)) => anyhow::bail!("Unable to read public key for JWT token verification"),
63 (Some(_), None) => anyhow::bail!("Unable to read private key for JWT token signing"),
64 };
65
66 key_pair.try_into()
67}
68
69pub struct EcKeyPair {
71 pub public_key_bytes: Vec<u8>,
72 pub private_key_bytes: Vec<u8>,
73}
74
75impl TryFrom<EcKeyPair> for JwtKeys {
76 type Error = anyhow::Error;
77 fn try_from(pair: EcKeyPair) -> anyhow::Result<Self> {
78 JwtKeys::new(pair.public_key_bytes, &pair.private_key_bytes)
79 }
80}
81
82impl EcKeyPair {
83 pub fn new(public_key_bytes: Vec<u8>, private_key_bytes: Vec<u8>) -> Self {
84 Self {
85 public_key_bytes,
86 private_key_bytes,
87 }
88 }
89
90 pub fn generate() -> anyhow::Result<Self> {
91 let group = EcGroup::from_curve_name(Nid::X9_62_PRIME256V1)?;
93
94 let eckey = EcKey::generate(&group)?;
96
97 let pkey = PKey::from_ec_key(eckey.clone())?;
99
100 let private_key_bytes = pkey.private_key_to_pem_pkcs8()?;
102
103 let public_key_bytes = eckey.public_key_to_pem()?;
105
106 Ok(Self {
107 public_key_bytes,
108 private_key_bytes,
109 })
110 }
111
112 pub fn write_to_files(&self, public_key_path: &PubKeyPath, private_key_path: &PrivKeyPath) -> anyhow::Result<()> {
113 public_key_path.write(&self.public_key_bytes)?;
114 private_key_path.write(&self.private_key_bytes)?;
115 Ok(())
116 }
117}