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 Documentation License: MIT OR Apache-2.0

A specialized Rust library that implements the OAuth 2.0 Device Authorization Grant (RFC 8628), 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:

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

Basic Example

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):

#[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

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

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

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:

Run an example:

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:

[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

# 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:

at your option.

Acknowledgments

  • RFC 8628 - 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.