Skip to main content

bamboo_agent/agent/llm/providers/copilot/auth/
device_code.rs

1use reqwest::Client;
2use serde::Deserialize;
3
4const GITHUB_CLIENT_ID: &str = "Iv1.b507a08c87ecfe98";
5const DEVICE_CODE_URL: &str = "https://github.com/login/device/code";
6
7/// Device code response from GitHub
8#[derive(Debug, Deserialize)]
9pub struct DeviceCodeResponse {
10    pub device_code: String,
11    pub user_code: String,
12    pub verification_uri: String,
13    #[serde(rename = "expires_in")]
14    pub expires_in: u64,
15    pub interval: u64,
16}
17
18/// Get device code from GitHub
19pub async fn get_device_code(client: &Client) -> Result<DeviceCodeResponse, String> {
20    let params = [("client_id", GITHUB_CLIENT_ID), ("scope", "read:user")];
21
22    let response = client
23        .post(DEVICE_CODE_URL)
24        .header("Accept", "application/json")
25        .header("User-Agent", "BambooCopilot/1.0")
26        .form(&params)
27        .send()
28        .await
29        .map_err(|e| format!("Failed to request device code: {}", e))?;
30
31    let status = response.status();
32    if !status.is_success() {
33        let text = response.text().await.unwrap_or_default();
34        return Err(format!(
35            "Device code request failed: HTTP {} - {}",
36            status, text
37        ));
38    }
39
40    let device_code: DeviceCodeResponse = response
41        .json()
42        .await
43        .map_err(|e| format!("Failed to parse device code response: {}", e))?;
44
45    Ok(device_code)
46}
47
48/// Present device code to user
49pub fn present_device_code(device_code: &DeviceCodeResponse) {
50    println!("\n╔════════════════════════════════════════════════════════════╗");
51    println!("║     🔐 GitHub Copilot Authorization Required              ║");
52    println!("╚════════════════════════════════════════════════════════════╝");
53    println!();
54    println!("  1. Open your browser and navigate to:");
55    println!("     {}", device_code.verification_uri);
56    println!();
57    println!("  2. Enter the following code:");
58    println!();
59    println!("     ┌─────────────────────────┐");
60    println!("     │  {:^23} │", device_code.user_code);
61    println!("     └─────────────────────────┘");
62    println!();
63    println!("  3. Click 'Authorize' and wait...");
64    println!();
65    println!(
66        "  ⏳ Waiting for authorization (expires in {} seconds)...",
67        device_code.expires_in
68    );
69    println!();
70}
71
72#[cfg(test)]
73mod tests {
74    use super::*;
75
76    #[test]
77    fn test_github_client_id() {
78        assert_eq!(GITHUB_CLIENT_ID, "Iv1.b507a08c87ecfe98");
79    }
80}