| Crates.io | axum-jwt-auth |
| lib.rs | axum-jwt-auth |
| version | 0.6.3 |
| created_at | 2023-07-28 05:21:56.870191+00 |
| updated_at | 2026-01-25 18:31:18.434349+00 |
| description | A simple JWT authentication middleware for Axum |
| homepage | |
| repository | https://github.com/cmackenzie1/axum-jwt-auth |
| max_upload_size | |
| id | 928150 |
| size | 327,742 |
JWT authentication middleware for Axum. Supports local keys and remote JWKS with automatic caching and refresh.
cargo add axum-jwt-auth
use axum::{routing::get, Router};
use axum_jwt_auth::{Claims, JwtDecoderState, LocalDecoder};
use jsonwebtoken::{DecodingKey, Algorithm, Validation};
use serde::{Deserialize, Serialize};
use std::sync::Arc;
#[derive(Serialize, Deserialize)]
struct MyClaims {
sub: String,
exp: usize,
}
async fn protected(user: Claims<MyClaims>) -> String {
format!("Hello, {}!", user.claims.sub)
}
#[tokio::main]
async fn main() {
let keys = vec![DecodingKey::from_secret(b"secret")];
let decoder = LocalDecoder::builder()
.keys(keys)
.validation(Validation::new(Algorithm::HS256))
.build()
.unwrap();
let state = JwtDecoderState {
decoder: Arc::new(decoder),
};
let app = Router::new()
.route("/protected", get(protected))
.with_state(state);
// Server will expect: Authorization: Bearer <jwt>
}
Validate JWTs using remote JWKS endpoints with automatic caching and refresh:
use axum_jwt_auth::{Claims, JwtDecoderState, RemoteJwksDecoder};
use jsonwebtoken::{Algorithm, Validation};
use std::sync::Arc;
#[tokio::main]
async fn main() {
let mut validation = Validation::new(Algorithm::RS256);
validation.set_audience(&["your-audience"]);
validation.set_issuer(&["your-issuer"]);
let decoder = RemoteJwksDecoder::builder()
.jwks_url("https://your-auth-provider.com/.well-known/jwks.json".to_string())
.validation(validation)
.build()
.unwrap();
let decoder = Arc::new(decoder);
// Initialize: fetch keys immediately and start background refresh task
let shutdown_token = decoder.initialize().await.expect("Failed to initialize JWKS decoder");
let state = JwtDecoderState { decoder };
let app = Router::new()
.route("/protected", get(protected))
.with_state(state);
// Later, during application shutdown:
shutdown_token.cancel();
}
The remote decoder:
kid (key ID)CancellationTokenExtract tokens from custom headers or cookies:
use axum_jwt_auth::{define_header_extractor, define_cookie_extractor};
define_header_extractor!(XAuthToken, "x-auth-token");
define_cookie_extractor!(AuthCookie, "auth_token");
async fn header_auth(user: Claims<MyClaims, HeaderTokenExtractor<XAuthToken>>) { }
async fn cookie_auth(user: Claims<MyClaims, CookieTokenExtractor<AuthCookie>>) { }
See the examples directory for complete working examples:
MIT - see LICENSE for details.