A generic, extensible Rust library for JWT (JSON Web Token) validation with JWKS (JSON Web Key Set) caching support.
Designed for flexibility: Mozambigue provides a trait-based architecture that makes it easy to add support for different JWT providers while maintaining type safety and zero serialization overhead.
- ✅ Generic architecture - Trait-based system supporting multiple JWT providers
- ✅ Zero serialization overhead - Direct field access via
StandardClaimstrait - ✅ JWT signature verification (RSA and Octet keys)
- ✅ Automatic JWKS fetching from OpenID configuration endpoints
- ✅ Configurable JWKS caching with TTL
- ✅ Secure audience validation - Validates against configured expected audiences
- ✅ Issuer and expiration validation
- Kubernetes - Service account token validation with namespace and service account extraction
- Okta - OAuth2/OIDC token validation (access tokens and ID tokens) with user identity, groups, and scopes
The architecture is ready for additional providers:
- Standard OIDC (email, name, profile)
- Auth0 (roles, permissions, metadata)
- Google Sign-In
- Azure AD / Entra ID
- Keycloak (realm roles, client roles)
- Any custom OIDC provider
Add this to your Cargo.toml:
[dependencies]
mozambigue = "0.1"use mozambigue::{KubernetesJwtVerifier, VerifyJwt};
#[tokio::main]
async fn main() -> Result<(), Box<dyn std::error::Error>> {
// Simple usage - one line setup
let verifier = KubernetesJwtVerifier::with_issuer(
"https://kubernetes.default.svc.cluster.local",
"my-service"
).await?;
// Verify a token
let token = "eyJhbGciOiJSUzI1NiIsInR5cCI6IkpXVCJ9...";
let identity = verifier.verify(token).await?;
println!("Service Account: {}", identity.service_account);
println!("Namespace: {}", identity.namespace);
Ok(())
}use mozambigue::{OktaJwtVerifier, VerifyJwt};
#[tokio::main]
async fn main() -> Result<(), Box<dyn std::error::Error>> {
let verifier = OktaJwtVerifier::with_issuer(
"https://your-org.okta.com/oauth2/default",
"api://default"
).await?;
let token = "eyJhbGciOiJSUzI1NiIsInR5cCI6IkpXVCJ9...";
let identity = verifier.verify(token).await?;
println!("Subject: {}", identity.subject);
if let Some(email) = &identity.email {
println!("Email: {email}");
}
if let Some(groups) = &identity.groups {
println!("Groups: {groups:?}");
}
Ok(())
}use mozambigue::{
JwtVerifier,
JwtVerifierConfig,
IdentityExtractor,
StandardClaims,
};
use serde::Deserialize;
// 1. Define your claims structure
#[derive(Deserialize)]
struct MyClaims {
iss: String,
sub: String,
aud: Vec<String>,
exp: i64,
custom_field: String,
}
// 2. Implement StandardClaims
impl StandardClaims for MyClaims {
fn iss(&self) -> &str { &self.iss }
fn sub(&self) -> &str { &self.sub }
fn aud(&self) -> &[String] { &self.aud }
fn exp(&self) -> i64 { self.exp }
}
// 3. Define your identity type
struct MyIdentity {
user_id: String,
custom_data: String,
}
// 4. Create your extractor
struct MyExtractor;
impl IdentityExtractor for MyExtractor {
type Claims = MyClaims;
type Identity = MyIdentity;
fn extract_identity(&self, claims: &Self::Claims)
-> mozambigue::Result<Self::Identity>
{
Ok(MyIdentity {
user_id: claims.sub.clone(),
custom_data: claims.custom_field.clone(),
})
}
}
// 5. Use it!
#[tokio::main]
async fn main() -> Result<(), Box<dyn std::error::Error>> {
let config = JwtVerifierConfig::new(
"https://my-issuer.example.com",
"my-audience"
);
let verifier = JwtVerifier::new(config, MyExtractor).await?;
let identity = verifier.verify("token").await?;
println!("User: {}", identity.user_id);
Ok(())
}mozambigue/
├── Generic Infrastructure
│ ├── JwtVerifier<E> - Generic verifier
│ ├── IdentityExtractor - Trait for extractors
│ ├── StandardClaims - Trait for claims access
│ └── VerifyJwt - Verification trait
│
└── providers/
├── kubernetes/ - Kubernetes implementation
│ ├── KubernetesClaims
│ ├── KubernetesIdentity
│ ├── KubernetesExtractor
│ └── KubernetesJwtVerifier
│
└── okta/ - Okta implementation
├── OktaClaims
├── OktaIdentity
├── OktaExtractor
└── OktaJwtVerifier
- Token Parsing: Parse JWT to extract issuer (without validation)
- JWKS Fetching: Fetch JWKS from
{issuer}/.well-known/openid-configuration(cached) - Signature Verification: Verify signature using key from JWKS
- Claims Validation: Validate issuer, expiration, and audience
- Identity Extraction: Provider-specific extraction via
IdentityExtractortrait
use mozambigue::{KubernetesJwtVerifier, JwtVerifierConfig, KubernetesExtractor};
use std::time::Duration;
let config = JwtVerifierConfig::new(
"https://kubernetes.default.svc.cluster.local",
"my-service"
)
.with_cache_ttl(Duration::from_secs(1800)); // 30 minutes
let verifier = JwtVerifier::new(config, KubernetesExtractor).await?;
let identity = verifier.verify(token).await?;use mozambigue::JwtVerifierConfig;
let config = JwtVerifierConfig::new_with_audiences(
"https://your-issuer.example.com",
vec!["service-a".to_string(), "service-b".to_string()]
)?
.with_cache_ttl(Duration::from_secs(3600));
let verifier = JwtVerifier::new(config, KubernetesExtractor).await?;let custom_client = reqwest::Client::builder()
.timeout(Duration::from_secs(10))
.build()?;
let config = JwtVerifierConfig::new(
"https://your-issuer.example.com",
"my-service"
)
.with_http_client(custom_client);
let verifier = JwtVerifier::new(config, KubernetesExtractor).await?;use mozambigue::JwtVerifier;
use mozambigue::providers::kubernetes::{
KubernetesExtractor,
KubernetesIdentity,
};
let verifier = JwtVerifier::new(config, KubernetesExtractor).await?;
let identity: KubernetesIdentity = verifier.verify(token).await?;Efficient caching reduces network calls:
- Configurable TTL (default: 1 hour)
- Automatic cache expiration
- Thread-safe with
Arc<RwLock<HashMap>> - Per-issuer caching
Want to add support for Auth0, Google, or your custom OIDC provider? It's easy:
- Define your claims structure with provider-specific fields
- Implement
StandardClaimsfor standard field access - Define your identity type with extracted information
- Implement
IdentityExtractorwith your extraction logic
See the Kubernetes provider for a complete example.
See the examples directory:
cargo run --example basic_usage
cargo run --example okta_usageLicensed under either of:
- Apache License, Version 2.0 (LICENSE-APACHE or http://www.apache.org/licenses/LICENSE-2.0)
- MIT license (LICENSE-MIT or http://opensource.org/licenses/MIT)
at your option.