use std::collections::HashMap;
use serde::{Deserialize, Serialize};
use crate::{errors::Error, FirebaseAuth};
#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Eq)]
pub struct Jwk {
pub e: String,
pub alg: String,
pub kty: String,
pub kid: String,
pub n: String,
}
impl Jwk {
const EXPONENT: &'static str = "AQAB";
const ALGORITHM: &'static str = "RS256";
const KEY_TYPE: &'static str = "RSA";
pub fn new(kid: &str, n: &str) -> Self {
Self {
e: Self::EXPONENT.to_string(),
alg: Self::ALGORITHM.to_string(),
kty: Self::KEY_TYPE.to_string(),
kid: kid.to_string(),
n: n.to_string(),
}
}
}
#[derive(Debug, Clone, Deserialize)]
pub struct JwksResponse {
pub keys: Vec<Jwk>,
}
impl FirebaseAuth {
pub(crate) async fn jwks(&self) -> Result<HashMap<String, Jwk>, Error> {
let response = self.client.get(&self.jwks_url).send().await?;
let jwks: JwksResponse = response.json().await?;
let table =
jwks.keys
.into_iter()
.fold(HashMap::<String, Jwk>::new(), |mut key_map, jwk| {
key_map.insert(jwk.kid.clone(), jwk);
key_map
});
Ok(table)
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_jwk_new() {
let actual_jwk = Jwk::new("test-kid", "test-n");
let desired_jwk = Jwk {
e: "AQAB".to_string(),
alg: "RS256".to_string(),
kty: "RSA".to_string(),
kid: "test-kid".to_string(),
n: "test-n".to_string(),
};
assert_eq!(actual_jwk, desired_jwk);
}
}