axum-oidc-client
A comprehensive OAuth2/OIDC authentication library for Axum web applications with PKCE (Proof Key for Code Exchange) support and token auto refresh capabilities.
Features
- ✅ OAuth2/OIDC Authentication - Full support for OAuth2 and OpenID Connect protocols
- 🔐 PKCE Support - Implements RFC 7636 for enhanced security
- 🔄 Automatic Token Refresh - Seamlessly refreshes expired ID tokens and access tokens using OAuth2 refresh token flow
- 💾 Flexible Caching - Pluggable cache backends with built-in Redis support
- 🍪 Secure Sessions - Encrypted cookie-based session management
- 🚪 Logout Handlers - Support for both standard and OIDC logout flows
- 🎯 Type-safe Extractors - Convenient extractors for authenticated users and sessions
- 🔧 Customizable - Extensible with custom CA certificates and logout handlers
- ⚡ Production Ready - Battle-tested with comprehensive error handling
Installation
Add this to your Cargo.toml:
[]
= "0.1.0"
= "0.7"
= { = "1", = ["full"] }
Feature Flags
redis- Enable Redis cache backend with default TLS (enabled by default)redis-rustls- Enable Redis with rustls for TLSredis-native-tls- Enable Redis with native-tls
[]
= { = "0.1.0", = ["redis"] }
Quick Start
use ;
use ;
use Arc;
async
async
// This route requires authentication
async
Automatic ID Token and Access Token Refresh
The library automatically refreshes expired ID tokens and access tokens when they expire. This happens transparently when you use the provided extractors.
How It Works
- Token Expiration Check - On each request, the library checks if the ID token and access token have expired
- Automatic Refresh - If expired, uses the refresh token to obtain new ID token and access token
- Session Update - Updates the session with the new ID token, access token, and expiration time
- Cache Sync - Saves the refreshed session back to the cache
- Seamless Access - Your handler receives the fresh token automatically
Using Auto-Refresh Extractors
use ;
use AuthSession;
// Access token extractor with automatic refresh
async
// ID token extractor with automatic refresh
async
// Full session extractor with automatic token refresh
async
Extractors with Automatic Token Refresh
AccessToken- Extracts the access token (automatically refreshed if expired)IdToken- Extracts the ID token (automatically refreshed if expired)AuthSession- Extracts full session (ID token and access token automatically refreshed if expired)OptionalAccessToken- Optional access token (automatically refreshed if expired)OptionalIdToken- Optional ID token (automatically refreshed if expired)
Refresh Token Storage
Refresh tokens are automatically:
- Stored in the session during initial authentication
- Used to obtain new ID tokens and access tokens when they expire
- Updated if the provider issues a new refresh token during refresh
- Persisted in the cache with the session
API Documentation
Core Modules
auth
The core authentication module providing the main layer and configuration types.
Key Types:
AuthLayer- Tower layer for adding authentication to your Axum appOAuthConfiguration- Configuration for OAuth2 endpoints and credentialsCodeChallengeMethod- PKCE code challenge method (S256 or Plain)LogoutHandler- Trait for implementing custom logout behavior
auth_builder
Builder pattern for constructing OAuth configurations.
Example:
use OAuthConfigurationBuilder;
let config = default
.with_client_id
.with_client_secret
.with_redirect_uri
.with_authorization_endpoint
.with_token_endpoint
.with_private_cookie_key
.with_scopes
.build?;
auth_cache
Cache trait and implementations for storing authentication state.
Trait:
Built-in Implementations:
redis::AuthCache- Redis-backed cache (requiresredisfeature)
Custom Implementation:
use AuthCache;
use async_trait;
;
auth_session
Session management and token handling.
Key Type:
AuthSession- Contains authenticated user's session data
Fields:
extractors
Type-safe extractors for accessing authenticated user data with automatic ID token and access token refresh.
Available Extractors:
AuthSession- Full session (automatically refreshes ID token and access token if expired), redirects to OAuth if not authenticatedAccessToken- Access token extractor (automatically refreshes if expired)IdToken- ID token extractor (automatically refreshes if expired)OptionalAccessToken- Optional access token (automatically refreshes if expired)OptionalIdToken- Optional ID token (automatically refreshes if expired)
Example:
use AuthSession;
use ;
// Protected route with full session
async
// Protected route with just access token
async
// Protected route with ID token
async
// Public route with optional authentication
async
logout
Logout handler implementations.
Built-in Handlers:
-
DefaultLogoutHandler - Simple local logout with session cleanup
Use this handler when:
- The OAuth provider doesn't support OIDC logout (e.g., Google, GitHub)
- You only need to clear the local session without notifying the provider
- You're implementing custom logout logic
use DefaultLogoutHandler; let handler = new;Behavior:
- Removes session cookie
- Deletes session from cache
- Redirects to
post_logout_redirect_uri(default: "/")
-
OidcLogoutHandler - OIDC-compliant logout with provider notification
Use this handler when:
- The OAuth provider supports OIDC RP-Initiated Logout (e.g., Keycloak, Azure AD)
- You need to end the session at the provider
- You want single logout across multiple applications
use OidcLogoutHandler; let handler = new;Behavior:
- Removes session cookie
- Deletes session from cache
- Redirects to provider's
end_session_endpointwithid_token_hint - Provider logs out user and redirects to
post_logout_redirect_uri
Custom Handler:
You can implement the LogoutHandler trait to create custom logout behavior:
use LogoutHandler;
use BoxFuture;
use ;
Automatic Routes
The AuthLayer automatically adds the following routes (default base path is /auth):
GET /auth- Initiates OAuth2 authorization flowGET /auth/callback- OAuth2 callback endpoint (handles authorization code exchange)GET /auth/logout- Logout endpoint (redirects to home by default)GET /auth/logout?redirect=/path- Logout with custom redirect
Configurable Base Path
You can customize the base path for authentication routes via configuration:
let config = default
// ... other config
.with_base_path // Custom base path (default: "/auth")
.with_redirect_uri // Match your base_path
.build?;
// Routes will be available at:
// - GET /api/auth
// - GET /api/auth/callback
// - GET /api/auth/logout
Configuration
Required Configuration
default
.with_client_id // OAuth2 client ID
.with_client_secret // OAuth2 client secret
.with_redirect_uri // Callback URL
.with_authorization_endpoint // Authorization URL
.with_token_endpoint // Token exchange URL
.with_private_cookie_key // Session encryption key (min 32 bytes)
.with_session_max_age // Session duration in minutes
.build?;
Optional Configuration
builder
.with_scopes // OAuth scopes (default: openid, email, profile)
.with_code_challenge_method // PKCE method (default: S256)
.with_end_session_endpoint // OIDC logout endpoint (only for OIDC-compliant providers)
.with_post_logout_redirect_uri // Post-logout redirect (default: "/")
.with_custom_ca_cert // Custom CA certificate
.with_token_max_age // Token max age in seconds
.with_base_path // Custom base path for auth routes (default: "/auth")
Note on end_session_endpoint:
- Only set this if your OAuth provider supports OIDC RP-Initiated Logout
- Use with
OidcLogoutHandlerto properly logout from the provider - Not all providers support this (e.g., Google, GitHub don't implement OIDC logout)
OAuth Providers
Google supports OAuth2 but does not implement OIDC logout. Use DefaultLogoutHandler for logout.
use DefaultLogoutHandler;
let config = default
.with_authorization_endpoint
.with_token_endpoint
.with_client_id
.with_client_secret
.with_redirect_uri
.with_private_cookie_key
.with_scopes
.with_session_max_age
// Note: DO NOT set end_session_endpoint for Google
.build?;
let logout_handler = new;
GitHub
GitHub uses OAuth2 (not OIDC). Use DefaultLogoutHandler for logout.
use DefaultLogoutHandler;
let config = default
.with_authorization_endpoint
.with_token_endpoint
.with_client_id
.with_client_secret
.with_redirect_uri
.with_private_cookie_key
.with_scopes
.with_session_max_age
// Note: GitHub doesn't support OIDC logout
.build?;
let logout_handler = new;
Keycloak
Keycloak fully supports OIDC including RP-Initiated Logout. Use OidcLogoutHandler.
use OidcLogoutHandler;
let realm = "your-realm";
let keycloak_url = "https://keycloak.example.com";
let config = default
.with_authorization_endpoint
.with_token_endpoint
.with_end_session_endpoint
.with_client_id
.with_client_secret
.with_redirect_uri
.with_post_logout_redirect_uri
.with_private_cookie_key
.with_scopes
.with_session_max_age
.build?;
// Use OidcLogoutHandler with the end_session_endpoint
let logout_handler = new;
Microsoft Azure AD
Azure AD supports OIDC logout. Use OidcLogoutHandler.
use OidcLogoutHandler;
let tenant = "common"; // or your tenant ID
let config = default
.with_authorization_endpoint
.with_token_endpoint
.with_end_session_endpoint
.with_client_id
.with_client_secret
.with_redirect_uri
.with_post_logout_redirect_uri
.with_private_cookie_key
.with_scopes
.with_session_max_age
.build?;
// Use OidcLogoutHandler for Azure AD
let logout_handler = new;
Provider Compatibility Summary
| Provider | OIDC Support | Logout Support | Recommended Handler |
|---|---|---|---|
| Partial | ❌ No OIDC logout | DefaultLogoutHandler |
|
| GitHub | ❌ OAuth2 only | ❌ No OIDC logout | DefaultLogoutHandler |
| Keycloak | ✅ Full | ✅ RP-Initiated Logout | OidcLogoutHandler |
| Azure AD | ✅ Full | ✅ RP-Initiated Logout | OidcLogoutHandler |
| Okta | ✅ Full | ✅ RP-Initiated Logout | OidcLogoutHandler |
| Auth0 | ✅ Full | ✅ RP-Initiated Logout | OidcLogoutHandler |
Security Considerations
PKCE Code Challenge Method
Always use CodeChallengeMethod::S256 in production. The Plain method is only for testing or legacy systems that don't support S256.
.with_code_challenge_method // ✅ Recommended
.with_code_challenge_method // ⚠️ Not recommended
Private Cookie Key
Use a cryptographically strong random value for the private cookie key:
// ✅ Good: Generate with a tool like openssl
// openssl rand -base64 64
.with_private_cookie_key
// ❌ Bad: Hardcoded or weak key
.with_private_cookie_key
HTTPS in Production
Always use HTTPS for all endpoints in production:
// ✅ Production
.with_redirect_uri
// ⚠️ Development only
.with_redirect_uri
Session and Token Expiration
Configure appropriate expiration times based on your security requirements:
.with_session_max_age // 30 minutes - balance between UX and security
.with_token_max_age // 5 minutes - force token refresh
Advanced Usage
Custom Auth Routes Base Path
You can mount authentication routes at a custom base path instead of the default /auth:
use ;
use ;
use Arc;
async
async
async
Key Points:
- Use
.with_base_path("/api/auth")in the configuration builder to set a custom base path - Update your
redirect_uriin the configuration to match:http://localhost:8080/api/auth/callback - Update your OAuth provider settings with the new redirect URI
- The base path can be any valid path (e.g.,
/oauth,/api/v1/auth, etc.) - Trailing slashes are automatically removed
- Default is
/authif not specified
Examples
See the examples/sample-server directory for a complete working example with:
- Environment variable configuration
- CLI argument parsing
- Multiple route types (public and protected)
- Redis cache integration
- Custom logout handling
Run the example:
Error Handling
The library uses a custom Error type for all operations:
use Error;
match config.build
Testing
# Run all tests
# Run with specific features
# Run example
Contributing
Contributions are welcome! Please feel free to submit a Pull Request.
License
This project is licensed under the MIT License - see the LICENSE file for details.
Acknowledgments
- Built on top of Axum
- Uses pkce for PKCE implementation
- Session management with tower-cookies