oauth 0.0.2

Universal OAuth 2.0 adapter for Rust web frameworks
Documentation
# 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