# OAuth Adapter for Rust Web Frameworks
A universal OAuth 2.0 adapter for Rust web frameworks, providing a single configuration model and framework-specific glue so you can expose compliant token endpoints without duplicating logic.
> **Status:** This crate is still in active development. The API described below represents the intended shape of the crate and may change before the first stable release.
## Highlights
- Framework agnostic support for Axum, Warp, Actix-web, and Rocket
- Shared `OAuthConfig` builder for consistent client credentials and token settings
- Pluggable token store interface for Redis, SQL, or in-memory implementations
- Opinionated defaults with escape hatches for custom validation and token generation
## Notice
⚠️ **This crate is in early development.** For production use, consider [oauth2](https://crates.io/crates/oauth2) as a mature alternative solution.
## Installation
Add the crate to your `Cargo.toml`, enabling the integration you need:
```toml
[dependencies]
oauth = { version = "0.1.0", default-features = false, features = ["axum"] }
```
Available feature flags: `axum`, `warp`, `actix`, `rocket`. Combine them if you support multiple frameworks in the same binary.
## Configuration At A Glance
Create an `OAuthConfig` once and share it across the adapters you enable:
```rust
use oauth::OAuthConfig;
let config = OAuthConfig::builder()
.client_id("your-client-id")
.client_secret("your-client-secret")
.issuer("https://auth.example.com")
.access_token_ttl(std::time::Duration::from_secs(3600))
.refresh_token_ttl(std::time::Duration::from_secs(7 * 24 * 3600))
.enable_refresh_tokens(true)
.build()
.expect("valid OAuth configuration");
```
The builder validates required fields and returns a `Result<OAuthConfig, ConfigError>`. Keep the resulting value in an `Arc` if you need to clone it between routes or filters.
### Custom Token Storage
To persist tokens outside the default in-memory store, implement `TokenStore` and attach it to the configuration:
```rust
use oauth::{OAuthConfig, TokenStore, TokenRecord};
struct CustomTokenStore;
impl TokenStore for CustomTokenStore {
fn save(&self, token: TokenRecord) -> oauth::Result<()> {
// Write to Redis, PostgreSQL, or another backend
todo!("store token: {token:?}");
}
fn revoke(&self, token_id: &str) -> oauth::Result<()> {
// Remove the token from your backend
todo!("revoke token: {token_id}");
}
}
let config = OAuthConfig::builder()
.client_id("your-client-id")
.client_secret("your-client-secret")
.token_store(CustomTokenStore)
.build()
.expect("valid OAuth configuration with custom store");
```
## Framework Quick Starts
Each framework-specific integration exposes a thin wrapper that turns an `OAuthConfig` into the appropriate route handler.
### Axum
```rust
use std::sync::Arc;
use axum::{routing::post, Router};
use oauth::axum::OAuthHandler;
use oauth::OAuthConfig;
#[tokio::main]
async fn main() {
let config = Arc::new(
OAuthConfig::builder()
.client_id("your-client-id")
.client_secret("your-client-secret")
.build()
.expect("valid OAuth configuration"),
);
let oauth = OAuthHandler::from_config(config.clone());
let app = Router::new().route("/oauth/token", post(oauth.token_endpoint()));
axum::Server::bind(&"0.0.0.0:3000".parse().unwrap())
.serve(app.into_make_service())
.await
.unwrap();
}
```
### Warp
```rust
use std::sync::Arc;
use oauth::warp::oauth_filter;
use oauth::OAuthConfig;
use warp::Filter;
#[tokio::main]
async fn main() {
let config = Arc::new(
OAuthConfig::builder()
.client_id("your-client-id")
.client_secret("your-client-secret")
.build()
.expect("valid OAuth configuration"),
);
let oauth_route = warp::path!("oauth" / "token")
.and(oauth_filter(config.clone()));
warp::serve(oauth_route)
.run(([0, 0, 0, 0], 3000))
.await;
}
```
### Actix-web
```rust
use std::sync::Arc;
use actix_web::{App, HttpServer};
use oauth::actix::configure_oauth;
use oauth::OAuthConfig;
#[actix_web::main]
async fn main() -> std::io::Result<()> {
let config = Arc::new(
OAuthConfig::builder()
.client_id("your-client-id")
.client_secret("your-client-secret")
.build()
.expect("valid OAuth configuration"),
);
HttpServer::new(move || {
App::new().configure(|cfg| configure_oauth(cfg, config.clone()))
})
.bind(("0.0.0.0", 3000))?
.run()
.await
}
```
### Rocket
```rust
use std::sync::Arc;
use oauth::rocket::oauth_routes;
use oauth::OAuthConfig;
use rocket::launch;
#[launch]
fn rocket() -> _ {
let config = Arc::new(
OAuthConfig::builder()
.client_id("your-client-id")
.client_secret("your-client-secret")
.build()
.expect("valid OAuth configuration"),
);
rocket::build().mount("/", oauth_routes(config))
}
```
## Supported OAuth 2.0 Grants
The adapter aims to cover the following grant types out of the box:
- Client Credentials
- Authorization Code (with PKCE support)
- Refresh Token
Additional flows (Device Code, Resource Owner Password) are planned once the core API stabilizes.
## Token Endpoint Contract
All integrations expose a standardized token endpoint that accepts JSON requests:
```json
{
"grant_type": "client_credentials",
"client_id": "your-client-id",
"client_secret": "your-client-secret",
"scope": "read:payments write:payments"
}
```
Successful responses return RFC 6749-compliant JSON:
```json
{
"access_token": "eyJhbGciOiJSUzI1NiIsInR5cCI6IkpXVCJ9...",
"token_type": "Bearer",
"expires_in": 3600,
"refresh_token": "optional-refresh-token"
}
```
## Contributing
We welcome pull requests and issues that help shape the API.
1. Fork the repository
2. Create a feature branch (`git checkout -b feature/amazing-feature`)
3. Commit (`git commit -m "feat: add amazing feature"`)
4. Push (`git push origin feature/amazing-feature`)
5. Open a Pull Request
## License
Distributed under the MIT License. See the [LICENSE](LICENSE) file for details.
## Acknowledgements
- Inspired by the need for a unified OAuth solution across Rust web frameworks
- Built with ❤️ for the Rust community