fix: token validation

This commit is contained in:
pavel 2026-02-11 00:14:27 +01:00
commit 844677cc27
2 changed files with 37 additions and 11 deletions

View file

@ -10,10 +10,17 @@ pub struct Claims {
pub exp: usize, pub exp: usize,
pub iat: usize, pub iat: usize,
pub iss: String, pub iss: String,
pub aud: String, pub aud: Audience,
} }
#[derive(Debug, Deserialize)] #[derive(Debug, Serialize, Deserialize)]
#[serde(untagged)]
pub enum Audience {
Single(String),
Multiple(Vec<String>),
}
#[derive(Debug, Deserialize, Clone)]
struct Jwk { struct Jwk {
#[serde(rename = "kty")] #[serde(rename = "kty")]
_kty: String, _kty: String,
@ -31,13 +38,17 @@ struct Jwks {
pub struct JwksVerifier { pub struct JwksVerifier {
issuer: String, issuer: String,
audience: String,
jwks_uri: String, jwks_uri: String,
keys: Arc<RwLock<Vec<Jwk>>>, keys: Arc<RwLock<Vec<Jwk>>>,
client: Client, client: Client,
} }
impl JwksVerifier { impl JwksVerifier {
pub async fn new(issuer: String) -> Result<Self, Box<dyn std::error::Error>> { pub async fn new(
issuer: String,
audience: String,
) -> Result<Self, Box<dyn std::error::Error>> {
let client = Client::new(); let client = Client::new();
// Authentik OIDC discovery // Authentik OIDC discovery
let discovery_url = format!( let discovery_url = format!(
@ -53,6 +64,7 @@ impl JwksVerifier {
let verifier = Self { let verifier = Self {
issuer, issuer,
audience,
jwks_uri, jwks_uri,
keys: Arc::new(RwLock::new(Vec::new())), keys: Arc::new(RwLock::new(Vec::new())),
client, client,
@ -73,18 +85,29 @@ impl JwksVerifier {
let header = decode_header(token)?; let header = decode_header(token)?;
let kid = header.kid.ok_or("Missing kid in token header")?; let kid = header.kid.ok_or("Missing kid in token header")?;
let keys = self.keys.read().await; let jwk = {
let jwk = keys let keys = self.keys.read().await;
.iter() keys.iter().find(|k| k.kid == kid).cloned()
.find(|k| k.kid == kid) };
.ok_or("Key not found in JWKS")?;
let jwk = match jwk {
Some(key) => key,
None => {
self.refresh_keys().await?;
let keys = self.keys.read().await;
keys.iter()
.find(|k| k.kid == kid)
.cloned()
.ok_or("Key not found in JWKS")?
}
};
let decoding_key = DecodingKey::from_rsa_components(&jwk.n, &jwk.e)?; let decoding_key = DecodingKey::from_rsa_components(&jwk.n, &jwk.e)?;
let mut validation = Validation::new(Algorithm::RS256); let mut validation = Validation::new(Algorithm::RS256);
validation.set_issuer(&[self.issuer.clone()]); validation.set_issuer(&[self.issuer.clone()]);
// Aud validation might need careful config, usually it's the client_id validation.set_audience(&[self.audience.clone()]);
validation.validate_aud = false; validation.validate_aud = true;
let token_data = decode::<Claims>(token, &decoding_key, &validation)?; let token_data = decode::<Claims>(token, &decoding_key, &validation)?;
Ok(token_data.claims) Ok(token_data.claims)

View file

@ -97,7 +97,10 @@ pub async fn start(db_url: &str) -> Result<(), Box<dyn std::error::Error>> {
let authentik_client_secret = let authentik_client_secret =
std::env::var("AUTHENTIK_CLIENT_SECRET").map_err(|_| "AUTHENTIK_CLIENT_SECRET not set")?; std::env::var("AUTHENTIK_CLIENT_SECRET").map_err(|_| "AUTHENTIK_CLIENT_SECRET not set")?;
let verifier = Arc::new(crate::auth::JwksVerifier::new(authentik_issuer.clone()).await?); let verifier = Arc::new(
crate::auth::JwksVerifier::new(authentik_issuer.clone(), authentik_client_id.clone())
.await?,
);
let authenticator = Arc::new( let authenticator = Arc::new(
crate::auth::Authenticator::new( crate::auth::Authenticator::new(
authentik_issuer, authentik_issuer,