use std::error::Error; use std::fs::read_to_string; use oauth2::basic::BasicClient; use oauth2::reqwest::http_client; use oauth2::AccessToken; use oauth2::AuthUrl; use oauth2::ClientId; use oauth2::ClientSecret; use oauth2::TokenResponse; use oauth2::TokenUrl; mod types; use types::ClientAuth; pub fn run() -> Result<(), Box> { let client_auth = read_client_auth()?; println!("Client ID: {}", client_auth.id); println!("Client Secret: {}", client_auth.secret); let access_token = get_api_token(client_auth.id, client_auth.secret)?; println!("Access Token: {access_token:#?}"); Ok(()) } fn read_client_auth() -> Result> { let mut id = String::new(); let mut secret = String::new(); for line in read_to_string(".client-auth")?.lines() { let line_str = line.to_string(); let cur_line: Vec<&str> = line_str.split('=').collect(); if cur_line[0] == "client_id" { id = cur_line[1].to_string(); } else if cur_line[0] == "client_secret" { secret = cur_line[1].to_string(); } } Ok(ClientAuth { id, secret }) } fn get_api_token(client_id: String, client_secret: String) -> Result> { let client = BasicClient::new( ClientId::new(client_id), Some(ClientSecret::new(client_secret)), AuthUrl::new("https://api.tailscale.com/api/v2/oauth/token".to_string())?, Some(TokenUrl::new( "https://api.tailscale.com/api/v2/oauth/token".to_string(), )?), ); let token_result = client.exchange_client_credentials().request(http_client)?; let access_token = token_result.access_token().to_owned(); Ok(access_token) }