# OAuth Device Flows
[](https://crates.io/crates/oauth-device-flows)
[](https://docs.rs/oauth-device-flows)
[](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
| **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
| `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
| `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.