use oauth_device_flows::{DeviceFlow, DeviceFlowConfig, Provider};
use std::time::Duration;
#[tokio::main]
async fn main() -> Result<(), Box<dyn std::error::Error>> {
let config = DeviceFlowConfig::new()
.client_id("your-github-client-id") .scopes(vec![
"user:email", "repo", "read:org", ])
.poll_interval(Duration::from_secs(5))
.max_attempts(60);
let mut device_flow = DeviceFlow::new(Provider::GitHub, config)?;
println!("Starting GitHub OAuth Device Flow...");
let auth_response = device_flow.initialize().await?;
println!("\n🐙 GitHub Authentication Required");
println!("──────────────────────────────");
println!("1. Open this URL in your browser:");
println!(" {}", auth_response.verification_uri());
println!();
println!("2. Enter this code:");
println!(" {}", auth_response.user_code());
println!();
#[cfg(feature = "qr-codes")]
if let Ok(qr_code) = auth_response.generate_qr_code() {
println!("Or scan this QR code:");
println!("{}", qr_code);
println!();
}
println!("⏳ Waiting for you to complete authentication...");
println!(
" (This will timeout in {} seconds)",
auth_response.expires_in().as_secs()
);
println!();
match device_flow.poll_for_token().await {
Ok(token_response) => {
println!("✅ Authentication successful!");
println!(" Token type: {}", token_response.token_type);
println!(" Scopes: {:?}", token_response.scope);
let token_manager = oauth_device_flows::TokenManager::new(
token_response,
Provider::GitHub,
DeviceFlowConfig::new().client_id("your-github-client-id"),
)?;
println!("\n🚀 Making API call to GitHub...");
let client = reqwest::Client::new();
let user_response = client
.get("https://api.github.com/user")
.header("Authorization", token_manager.authorization_header())
.header("User-Agent", "oauth-device-flows-example")
.send()
.await?;
if user_response.status().is_success() {
let user_info: serde_json::Value = user_response.json().await?;
println!(
" User: {}",
user_info["login"].as_str().unwrap_or("Unknown")
);
println!(
" Name: {}",
user_info["name"].as_str().unwrap_or("Unknown")
);
println!(
" Public repos: {}",
user_info["public_repos"].as_u64().unwrap_or(0)
);
} else {
println!(" User API call failed: {}", user_response.status());
}
let repos_response = client
.get("https://api.github.com/user/repos?per_page=5&sort=updated")
.header("Authorization", token_manager.authorization_header())
.header("User-Agent", "oauth-device-flows-example")
.send()
.await?;
if repos_response.status().is_success() {
let repos: serde_json::Value = repos_response.json().await?;
if let Some(repos_array) = repos.as_array() {
println!("\n📚 Recent repositories:");
for repo in repos_array.iter().take(5) {
let name = repo["name"].as_str().unwrap_or("Unknown");
let language = repo["language"].as_str().unwrap_or("Unknown");
let updated = repo["updated_at"].as_str().unwrap_or("Unknown");
println!(" • {} ({}) - last updated: {}", name, language, updated);
}
}
} else {
println!(" Repos API call failed: {}", repos_response.status());
}
}
Err(e) => {
eprintln!("❌ Authentication failed: {}", e);
match e {
oauth_device_flows::DeviceFlowError::AuthorizationDenied => {
eprintln!(" The user denied the authorization request.");
}
oauth_device_flows::DeviceFlowError::ExpiredToken => {
eprintln!(" The device code expired. Please try again.");
}
oauth_device_flows::DeviceFlowError::MaxAttemptsExceeded(max) => {
eprintln!(" Timed out after {} attempts. Please try again.", max);
}
_ => {
eprintln!(" Error details: {}", e);
}
}
}
}
Ok(())
}