use crate::auth::error::AuthError;
use jsonwebtoken::DecodingKey;
use serde::{Deserialize, Serialize};
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct Jwk {
#[serde(skip_serializing_if = "Option::is_none")]
pub kid: Option<String>,
pub kty: String,
#[serde(skip_serializing_if = "Option::is_none")]
pub alg: Option<String>,
#[serde(skip_serializing_if = "Option::is_none")]
pub n: Option<String>,
#[serde(skip_serializing_if = "Option::is_none")]
pub e: Option<String>,
#[serde(skip_serializing_if = "Option::is_none")]
pub crv: Option<String>,
#[serde(skip_serializing_if = "Option::is_none")]
pub x: Option<String>,
}
impl Jwk {
pub fn to_decoding_key(&self) -> Result<DecodingKey, AuthError> {
match self.kty.as_str() {
"RSA" => {
let n = self
.n
.as_ref()
.ok_or_else(|| AuthError::Token("Missing 'n' component in JWK".to_string()))?;
let e = self
.e
.as_ref()
.ok_or_else(|| AuthError::Token("Missing 'e' component in JWK".to_string()))?;
DecodingKey::from_rsa_components(n, e).map_err(|e| AuthError::Token(e.to_string()))
}
"OKP" => {
match self.crv.as_deref() {
Some("Ed25519") => {}
Some(other) => {
return Err(AuthError::Token(format!(
"Unsupported OKP curve '{}' in JWK",
other
)));
}
None => {
return Err(AuthError::Token(
"Missing 'crv' component in OKP JWK".to_string(),
));
}
}
let x = self
.x
.as_ref()
.ok_or_else(|| AuthError::Token("Missing 'x' component in JWK".to_string()))?;
DecodingKey::from_ed_components(x).map_err(|e| AuthError::Token(e.to_string()))
}
other => Err(AuthError::Token(format!(
"Unsupported JWK 'kty' '{}' — only RSA and OKP are supported",
other
))),
}
}
}