oauth-device-flows 0.1.0

A specialized Rust library implementing OAuth 2.0 Device Authorization Grant (RFC 8628)
Documentation
# OAuth Device Flows


[![Crates.io](https://img.shields.io/crates/v/oauth-device-flows.svg)](https://crates.io/crates/oauth-device-flows)
[![Documentation](https://docs.rs/oauth-device-flows/badge.svg)](https://docs.rs/oauth-device-flows)
[![License: MIT OR Apache-2.0](https://img.shields.io/badge/license-MIT%20OR%20Apache--2.0-blue.svg)](https://github.com/yourusername/oauth-device-flows#license)

A specialized Rust library that implements the **OAuth 2.0 Device Authorization Grant** ([RFC 8628](https://tools.ietf.org/html/rfc8628)), commonly known as the "device flow" or "device code flow". This authentication flow is particularly useful for:

- 🖥️ **CLI applications** and command-line tools
- 📱 **Devices with limited input capabilities** (smart TVs, IoT devices)
- 🖱️ **Headless systems** where opening a browser is impractical
- 🔒 **Secure authentication** without embedding client secrets

## Features


- **Complete RFC 8628 implementation** with all error handling
- 🏢 **Multiple OAuth providers**: Microsoft, Google, GitHub, GitLab, and generic providers
-**Async/await support** with Tokio
- 🔄 **Token refresh** and lifecycle management
- 📱 **QR code generation** for easy mobile authentication (optional)
- 🛡️ **Secure token handling** using the `secrecy` crate
- 🎯 **Strong typing** for all OAuth request/response structures
- 📦 **Minimal dependencies** suitable for embedded use
- ⚙️ **Configurable polling strategies** with exponential backoff
- 🔧 **Builder pattern** for easy configuration

## Quick Start


Add to your `Cargo.toml`:

```toml
[dependencies]
oauth-device-flows = "0.1"
tokio = { version = "1.0", features = ["full"] }
```

### Basic Example


```rust
use oauth_device_flows::{DeviceFlow, DeviceFlowConfig, Provider};
use std::time::Duration;

#[tokio::main]

async fn main() -> Result<(), Box<dyn std::error::Error>> {
    // Configure the device flow
    let config = DeviceFlowConfig::new()
        .client_id("your-client-id")
        .scopes(vec!["user.read", "offline_access"])
        .poll_interval(Duration::from_secs(5))
        .max_attempts(60);
    
    // Create a device flow instance for Microsoft
    let mut device_flow = DeviceFlow::new(Provider::Microsoft, config)?;
    
    // Start the device authorization flow
    let auth_response = device_flow.initialize().await?;
    
    // Display information to the user
    println!("To sign in, use a web browser to open the page {} and enter the code {} to authenticate.",
        auth_response.verification_uri(),
        auth_response.user_code());
    
    // Poll for the token
    println!("Waiting for authentication...");
    let token_response = device_flow.poll_for_token().await?;
    
    // Create a token manager for automatic refresh
    let token_manager = oauth_device_flows::TokenManager::new(
        token_response,
        Provider::Microsoft,
        config
    )?;
    
    println!("Successfully authenticated!");
    println!("Access token: {}", token_manager.access_token());
    
    Ok(())
}
```

## Supported Providers


| Provider | Status | Client Secret Required | Refresh Tokens | Notes |
|----------|--------|----------------------|---------------|-------|
| **Microsoft** || No | Yes | Azure AD / Microsoft Entra |
| **Google** || Yes | Yes | Google Cloud / Workspace |
| **GitHub** || No | No | GitHub Apps |
| **GitLab** || Yes | Yes | GitLab.com and self-hosted |
| **Generic** || Configurable | Configurable | Custom OAuth providers |

## Advanced Usage


### With QR Codes


Enable the `qr-codes` feature (enabled by default):

```rust
#[cfg(feature = "qr-codes")]

if let Ok(qr_code) = auth_response.generate_qr_code() {
    println!("Scan this QR code with your mobile device:");
    println!("{}", qr_code);
}
```

### Token Management and Refresh


```rust
use oauth_device_flows::TokenManager;

// Create token manager
let mut token_manager = TokenManager::new(token_response, provider, config)?;

// Check if token is expired
if token_manager.is_expired() {
    token_manager.refresh().await?;
    println!("Token refreshed!");
}

// Get a valid token (automatically refreshes if needed)
let valid_token = token_manager.get_valid_token().await?;

// Use in HTTP requests
let auth_header = token_manager.authorization_header();
```

### Custom Provider Configuration


```rust
use oauth_device_flows::{Provider, GenericProviderConfig};
use url::Url;

let custom_config = GenericProviderConfig::new(
    Url::parse("https://custom-provider.com/device/code")?,
    Url::parse("https://custom-provider.com/token")?,
    "Custom Provider".to_string(),
)
.with_default_scopes(vec!["read".to_string(), "write".to_string()])
.with_client_secret_required(true);

let config = DeviceFlowConfig::new()
    .client_id("your-client-id")
    .client_secret("your-client-secret")
    .generic_provider(custom_config);

let device_flow = DeviceFlow::new(Provider::Generic, config)?;
```

### Error Handling


```rust
match device_flow.poll_for_token().await {
    Ok(token) => println!("Success!"),
    Err(oauth_device_flows::DeviceFlowError::AuthorizationDenied) => {
        println!("User denied the request");
    }
    Err(oauth_device_flows::DeviceFlowError::ExpiredToken) => {
        println!("Device code expired, please try again");
    }
    Err(oauth_device_flows::DeviceFlowError::MaxAttemptsExceeded(max)) => {
        println!("Timed out after {} attempts", max);
    }
    Err(e) => eprintln!("Other error: {}", e),
}
```

## Examples


The repository includes comprehensive examples for each supported provider:

- [`microsoft_device_flow.rs`]examples/microsoft_device_flow.rs - Microsoft/Azure AD authentication
- [`google_device_flow.rs`]examples/google_device_flow.rs - Google OAuth with refresh tokens
- [`github_device_flow.rs`]examples/github_device_flow.rs - GitHub App authentication

Run an example:

```bash
cargo run --example microsoft_device_flow
```

## Configuration Options


| Option | Description | Default |
|--------|-------------|---------|
| `client_id` | OAuth client identifier | Required |
| `client_secret` | OAuth client secret (if required) | None |
| `scopes` | Requested OAuth scopes | Provider defaults |
| `poll_interval` | How often to poll for token | 5 seconds |
| `max_attempts` | Maximum polling attempts | 60 (5 minutes) |
| `backoff_multiplier` | Exponential backoff factor | 1.1 |
| `max_poll_interval` | Maximum poll interval | 30 seconds |
| `request_timeout` | HTTP request timeout | 30 seconds |
| `use_pkce` | Enable PKCE (when supported) | Auto-detect |

## Cargo Features


| Feature | Description | Default |
|---------|-------------|---------|
| `qr-codes` | QR code generation support | Enabled |

Disable QR codes to reduce dependencies:

```toml
[dependencies]
oauth-device-flows = { version = "0.1", default-features = false }
```

## Security Considerations


- 🔐 **Secrets are protected** using the `secrecy` crate
- 🛡️ **No logging of sensitive data** (tokens, client secrets)
- 🔒 **Secure HTTP client** with rustls (no OpenSSL dependency)
-**Proper timeout handling** prevents hanging requests
-**Input validation** for all OAuth server responses

## Contributing


Contributions are welcome! Please feel free to submit a Pull Request. For major changes, please open an issue first to discuss what you would like to change.

### Development


```bash
# Clone the repository

git clone https://github.com/yourusername/oauth-device-flows.git
cd oauth-device-flows

# Run tests

cargo test

# Run examples

cargo run --example microsoft_device_flow

# Check documentation

cargo doc --open
```

## License


This project is dual-licensed under either:

- [MIT License]LICENSE-MIT
- [Apache License, Version 2.0]LICENSE-APACHE

at your option.

## Acknowledgments


- [RFC 8628]https://tools.ietf.org/html/rfc8628 - OAuth 2.0 Device Authorization Grant
- The Rust community for excellent HTTP and async libraries

---

**Note**: This library is not affiliated with any OAuth provider. Provider names and trademarks are the property of their respective owners.