| Crates.io | axum-oidc-layer |
| lib.rs | axum-oidc-layer |
| version | 0.1.0 |
| created_at | 2025-07-28 22:09:55.113899+00 |
| updated_at | 2025-07-28 22:09:55.113899+00 |
| description | A high-performance, configurable OIDC authentication layer for Axum web applications |
| homepage | https://github.com/adiepenbrock/axum-oidc-layer |
| repository | https://github.com/adiepenbrock/axum-oidc-layer |
| max_upload_size | |
| id | 1771639 |
| size | 98,016 |
A high-performance, configurable OIDC (OpenID Connect) authentication layer for Axum web applications. This crate provides JWT token validation with intelligent caching for optimal performance and supports pluggable cache backends.
kid (1h default TTL)Add to your Cargo.toml:
[dependencies]
axum-oidc-layer = "0.1"
axum = "0.8"
tokio = { version = "1.0", features = ["full"] }
use axum::{routing::get, Router};
use axum_oidc_layer::{OidcAuthenticationLayer, AuthenticationConfigProvider, Claims};
use std::time::Duration;
#[derive(Clone)]
struct AppConfig {
oidc_provider_url: String,
}
impl AuthenticationConfigProvider for AppConfig {
fn get_provider_url(&self) -> String {
self.oidc_provider_url.clone()
}
fn get_openid_configuration_url(&self) -> Option<String> {
None // Uses /.well-known/openid-configuration
}
// Optional: customize cache TTL
fn get_jwks_cache_ttl(&self) -> Duration {
Duration::from_secs(3600) // 1 hour
}
}
async fn protected_handler(claims: Claims) -> String {
format!("Hello, user {}!", claims.sub)
}
#[tokio::main]
async fn main() {
let config = AppConfig {
oidc_provider_url: "https://your-oidc-provider.com".to_string(),
};
let app = Router::new()
.route("/protected", get(protected_handler))
.layer(OidcAuthenticationLayer::<AppConfig, Claims>::new(config));
let listener = tokio::net::TcpListener::bind("0.0.0.0:3000").await.unwrap();
axum::serve(listener, app).await.unwrap();
}
Define your own claims structure:
use serde::{Deserialize, Serialize};
#[derive(Debug, Clone, Deserialize, Serialize)]
struct CustomClaims {
sub: String,
email: String,
roles: Vec<String>,
exp: usize,
}
// Use with the layer
let layer = OidcAuthenticationLayer::<AppConfig, CustomClaims>::new(config);
Implement your own cache (e.g., Redis):
use axum_oidc_layer::{JwksCache, OidcAuthenticationLayer};
use std::time::Duration;
struct RedisCache {
client: redis::Client,
}
impl JwksCache for RedisCache {
fn get(&self, key: &str) -> Option<String> {
// Your Redis GET implementation
todo!()
}
fn set(&self, key: &str, value: String, ttl: Duration) {
// Your Redis SET with TTL implementation
todo!()
}
}
// Use custom cache
let redis_cache = Arc::new(RedisCache::new("redis://localhost"));
let layer = OidcAuthenticationLayer::with_cache(config, redis_cache);
#[derive(Clone)]
struct EnvConfig;
impl AuthenticationConfigProvider for EnvConfig {
fn get_provider_url(&self) -> String {
std::env::var("OIDC_PROVIDER_URL")
.expect("OIDC_PROVIDER_URL must be set")
}
fn get_openid_configuration_url(&self) -> Option<String> {
std::env::var("OIDC_CONFIG_URL").ok()
}
fn get_jwks_cache_ttl(&self) -> Duration {
Duration::from_secs(
std::env::var("JWKS_CACHE_TTL")
.unwrap_or_else(|_| "3600".to_string())
.parse()
.unwrap_or(3600)
)
}
}
impl AuthenticationConfigProvider for Auth0Config {
fn get_provider_url(&self) -> String {
format!("https://{}.auth0.com", self.domain)
}
fn get_openid_configuration_url(&self) -> Option<String> {
Some(format!("https://{}.auth0.com/.well-known/openid-configuration", self.domain))
}
}
impl AuthenticationConfigProvider for KeycloakConfig {
fn get_provider_url(&self) -> String {
format!("{}/realms/{}", self.base_url, self.realm)
}
fn get_openid_configuration_url(&self) -> Option<String> {
Some(format!("{}/realms/{}/.well-known/openid-configuration",
self.base_url, self.realm))
}
}
impl AuthenticationConfigProvider for GoogleConfig {
fn get_provider_url(&self) -> String {
"https://accounts.google.com".to_string()
}
fn get_openid_configuration_url(&self) -> Option<String> {
Some("https://accounts.google.com/.well-known/openid-configuration".to_string())
}
}