Skip to main content

mecha10_auth/
lib.rs

1//! Mecha10 Authentication Library
2//!
3//! Shared authentication services for CLI and launcher.
4//!
5//! ## Features
6//!
7//! - Device code OAuth 2.0 flow (RFC 8628) for browser-based authentication
8//! - Credentials storage at ~/.mecha10/credentials.json
9//! - Support for custom auth server URLs via MECHA10_AUTH_URL environment variable
10//!
11//! ## Usage
12//!
13//! ```rust,no_run
14//! use mecha10_auth::{AuthService, CredentialsService};
15//!
16//! async fn login() -> anyhow::Result<()> {
17//!     let auth_service = AuthService::new();
18//!     let credentials_service = CredentialsService::new();
19//!
20//!     // Run device code flow
21//!     let credentials = auth_service.run_device_code_flow(|device_code| {
22//!         println!("Go to: {}", device_code.verification_uri);
23//!         println!("Enter code: {}", device_code.user_code);
24//!     }).await?;
25//!
26//!     // Save credentials
27//!     credentials_service.save(&credentials)?;
28//!     Ok(())
29//! }
30//! ```
31
32#![allow(
33    clippy::print_stdout,
34    clippy::print_stderr,
35    reason = "auth commands print interactive login/status output directly to the terminal for the CLI and launcher, by design"
36)]
37
38pub mod commands;
39mod credentials;
40mod service;
41pub mod types;
42
43pub use commands::ensure_authenticated_interactive;
44pub use credentials::{default_credentials_path, CredentialsService};
45pub use service::AuthService;
46pub use types::{AuthError, Credentials, DeviceCodeResponse, DeviceCodeStatus};
47
48pub const DEFAULT_AUTH_URL: &str = "https://mecha.industries/api/auth";
49
50pub const AUTH_URL_ENV_VAR: &str = "MECHA10_AUTH_URL";
51
52/// Get the auth URL, checking environment variable first
53///
54/// Priority:
55/// 1. MECHA10_AUTH_URL environment variable
56/// 2. DEFAULT_AUTH_URL constant
57pub fn get_auth_url() -> String {
58    mecha10_core::config::env_or_default(AUTH_URL_ENV_VAR, DEFAULT_AUTH_URL)
59}
60
61/// Display the device code flow instructions in a formatted box
62pub fn display_device_code_instructions(device_code: &DeviceCodeResponse) {
63    println!("┌────────────────────────────────────────────────────────┐");
64    println!("│  Open this URL in your browser:                        │");
65    println!("│                                                        │");
66    println!("│    {:<50}  │", device_code.verification_uri);
67    println!("│                                                        │");
68    println!("│  Then enter this code:                                 │");
69    println!("│                                                        │");
70    println!(
71        "│    {}                                        │",
72        device_code.user_code
73    );
74    println!("│                                                        │");
75    println!("└────────────────────────────────────────────────────────┘");
76    println!();
77    println!("Waiting for browser authorization...");
78    println!("(You can use a different device if this machine has no browser)");
79}
80
81/// Try to open the verification URL in the default browser
82pub fn open_browser(url: &str) {
83    let _ = open::that(url);
84}