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}