hb_auth/
cache.rs

1use serde::{Deserialize, Serialize};
2
3#[derive(Clone, Serialize, Deserialize)]
4pub struct CachedJwks {
5    pub keys: Vec<CachedJwk>,
6    pub fetched_at_ms: f64,
7}
8
9#[derive(Clone, Serialize, Deserialize)]
10pub struct CachedJwk {
11    pub kty: String,
12    pub kid: String,
13    pub n: String,
14    pub e: String,
15}
16
17impl CachedJwks {
18    pub fn is_expired(&self, now_ms: f64, ttl_ms: f64) -> bool {
19        now_ms - self.fetched_at_ms > ttl_ms
20    }
21}
22
23#[cfg(feature = "kv")]
24mod kv_cache {
25    use super::{CachedJwk, CachedJwks};
26    use js_sys::Date;
27    use worker::kv::KvStore;
28
29    const JWKS_CACHE_TTL_MS: f64 = 10.0 * 60.0 * 1000.0; // 10 minutes
30    const KV_TTL_SECONDS: u64 = 15 * 60; // 15 minutes (slightly longer than cache TTL)
31
32    fn cache_key(team_domain: &str) -> String {
33        format!("jwks:{}", team_domain)
34    }
35
36    pub async fn get_cached_jwks(kv: &KvStore, team_domain: &str) -> Option<CachedJwks> {
37        let key = cache_key(team_domain);
38
39        match kv.get(&key).json::<CachedJwks>().await {
40            Ok(Some(cached)) => {
41                if cached.is_expired(Date::now(), JWKS_CACHE_TTL_MS) {
42                    None
43                } else {
44                    Some(cached)
45                }
46            }
47            Ok(None) => None,
48            Err(_) => None,
49        }
50    }
51
52    pub async fn set_cached_jwks(
53        kv: &KvStore,
54        team_domain: &str,
55        keys: Vec<CachedJwk>,
56    ) -> Result<(), worker::Error> {
57        let key = cache_key(team_domain);
58        let cached = CachedJwks {
59            keys,
60            fetched_at_ms: Date::now(),
61        };
62
63        kv.put(&key, &cached)
64            .map_err(|e| worker::Error::RustError(format!("KV put error: {e}")))?
65            .expiration_ttl(KV_TTL_SECONDS)
66            .execute()
67            .await
68            .map_err(|e| worker::Error::RustError(format!("KV put error: {e}")))
69    }
70}
71
72#[cfg(feature = "kv")]
73pub use kv_cache::{get_cached_jwks, set_cached_jwks};