axum_jwt_auth/
lib.rs

1//! A Rust library for JWT authentication with support for both local keys and remote JWKS (JSON Web Key Sets).
2//!
3//! This crate provides a flexible JWT authentication system that can:
4//! - Validate tokens using local RSA/HMAC keys
5//! - Automatically fetch and cache remote JWKS endpoints
6//! - Integrate seamlessly with the Axum web framework
7//! - Handle token validation with configurable options
8//! - Extract tokens from multiple sources (headers or cookies)
9//!
10//! It builds on top of the `jsonwebtoken` crate to provide higher-level authentication primitives
11//! while maintaining full compatibility with standard JWT implementations.
12//!
13//! # Quick Start
14//!
15//! ## Using Bearer Tokens (Default)
16//!
17//! ```ignore
18//! use axum::{Router, routing::get, Json};
19//! use axum_jwt_auth::{Claims, LocalDecoder, JwtDecoderState};
20//! use serde::{Deserialize, Serialize};
21//!
22//! #[derive(Deserialize, Serialize)]
23//! struct MyClaims {
24//!     sub: String,
25//!     exp: usize,
26//! }
27//!
28//! async fn protected_handler(user: Claims<MyClaims>) -> Json<MyClaims> {
29//!     Json(user.claims)
30//! }
31//! ```
32//!
33//! ## Custom Token Extractors
34//!
35//! Use macros to easily define custom extractors:
36//!
37//! ```ignore
38//! use axum_jwt_auth::{define_header_extractor, define_cookie_extractor};
39//! use axum_jwt_auth::{Claims, HeaderTokenExtractor, CookieTokenExtractor};
40//!
41//! // Define custom extractors
42//! define_header_extractor!(XAuthToken, "x-auth-token");
43//! define_cookie_extractor!(AuthCookie, "auth_token");
44//!
45//! // Use in handlers
46//! async fn header_handler(user: Claims<MyClaims, HeaderTokenExtractor<XAuthToken>>) {
47//!     // Token extracted from "x-auth-token" header
48//! }
49//!
50//! async fn cookie_handler(user: Claims<MyClaims, CookieTokenExtractor<AuthCookie>>) {
51//!     // Token extracted from "auth_token" cookie
52//! }
53//! ```
54//!
55//! # Examples
56//!
57//! For full examples, see the [examples directory](https://github.com/cmackenzie1/axum-jwt-auth/blob/main/examples).
58
59mod axum;
60mod local;
61mod remote;
62
63use std::sync::Arc;
64
65use async_trait::async_trait;
66use jsonwebtoken::TokenData;
67use serde::de::DeserializeOwned;
68use thiserror::Error;
69
70pub use crate::axum::{
71    AuthError, BearerTokenExtractor, Claims, CookieTokenExtractor, ExtractorConfig,
72    HeaderTokenExtractor, JwtDecoderState, TokenExtractor,
73};
74pub use crate::local::LocalDecoder;
75pub use crate::remote::{
76    RemoteJwksDecoder, RemoteJwksDecoderBuilder, RemoteJwksDecoderConfig,
77    RemoteJwksDecoderConfigBuilder,
78};
79
80/// Errors that can occur during JWT decoding and validation.
81#[derive(Debug, thiserror::Error)]
82pub enum Error {
83    /// The JWT's `kid` (key ID) was not found in the key cache.
84    #[error("JWT key not found (kid: {0:?})")]
85    KeyNotFound(Option<String>),
86
87    /// Invalid decoder configuration (e.g., missing keys, algorithms, or audience).
88    #[error("Configuration error: {0}")]
89    Configuration(String),
90
91    /// JWT validation or decoding error from the `jsonwebtoken` crate.
92    #[error("JWT error: {0}")]
93    Jwt(#[from] jsonwebtoken::errors::Error),
94
95    /// HTTP request error when fetching remote JWKS.
96    #[error("HTTP request error: {0}")]
97    Reqwest(#[from] reqwest::Error),
98
99    /// JWKS refresh failed after exhausting all retry attempts.
100    #[error("JWKS refresh failed after {retry_count} attempts: {message}")]
101    JwksRefresh {
102        message: String,
103        retry_count: usize,
104        #[source]
105        source: Option<Box<dyn std::error::Error + Send + Sync>>,
106    },
107}
108
109/// Trait for decoding and validating JWT tokens.
110///
111/// Implemented by [`LocalDecoder`] and [`RemoteJwksDecoder`] to provide
112/// a unified interface for JWT validation with different key sources.
113#[async_trait]
114pub trait JwtDecoder<T>
115where
116    T: for<'de> DeserializeOwned,
117{
118    /// Decodes and validates a JWT token string, returning the parsed claims.
119    ///
120    /// # Errors
121    ///
122    /// Returns an error if the token is invalid, expired, has an invalid signature,
123    /// or if the key cannot be found (for remote decoders).
124    async fn decode(&self, token: &str) -> Result<TokenData<T>, Error>;
125}
126
127/// Type alias for a thread-safe, trait-object decoder suitable for Axum state.
128///
129/// Use this with `Arc::new(decoder)` to share a decoder across request handlers.
130pub type Decoder<T> = Arc<dyn JwtDecoder<T> + Send + Sync>;