A Rust library for integrating with the Runbeam Cloud API.
- Dual Authentication Support
- JWT Token Validation - RS256 signature verification with automatic JWKS caching
- Laravel Sanctum API Tokens - Server-side validation for simpler auth flows
- API Client - Comprehensive HTTP client for Runbeam Cloud API
- Gateway management (list, get, create, update, delete)
- Service management (list, get, create, update, delete)
- Endpoint, Backend, and Pipeline management
- Gateway authorization and token management
- Secure Token Storage - Automatic secure storage with OS keychain or encrypted filesystem
- Keyring (OS-native): macOS Keychain, Linux Secret Service, Windows Credential Manager
- Encrypted Filesystem fallback: age encryption with instance-specific keys
- No configuration required - automatically selects best option
- Machine Tokens - Autonomous gateway authentication with 30-day expiry
- Instance Isolation - Multiple instances can coexist with separate storage
- Cross-Platform - Works on macOS, Linux, and Windows
Add to your Cargo.toml:
[dependencies]
runbeam-sdk = "0.10.0"use runbeam_sdk::{
RunbeamClient,
validate_jwt_token,
save_token,
load_token,
MachineToken,
};
#[tokio::main]
async fn main() -> Result<(), Box<dyn std::error::Error>> {
// Validate user JWT token
let user_token = "eyJhbGci...";
let claims = validate_jwt_token(user_token, 24).await?;
// Create API client
let client = RunbeamClient::new(claims.api_base_url());
// Authorize gateway and get machine token
let response = client.authorize_gateway(
user_token,
"gateway-123",
None,
None
).await?;
// Save machine token securely (automatic storage selection)
let instance_id = "my-gateway"; // Unique identifier for this instance
let machine_token = MachineToken::new(
response.machine_token,
response.expires_at,
response.gateway.id,
response.gateway.code,
response.abilities,
);
save_token(instance_id, &machine_token).await?;
// Load token later
if let Some(token) = load_token(instance_id).await? {
if token.is_valid() {
println!("Token valid until: {}", token.expires_at);
}
}
Ok(())
}use runbeam_sdk::{
RunbeamClient,
save_token,
load_token,
MachineToken,
};
#[tokio::main]
async fn main() -> Result<(), Box<dyn std::error::Error>> {
// Create API client with base URL
let client = RunbeamClient::new("https://api.runbeam.io");
// Authorize gateway with Sanctum token (no validation needed)
// Sanctum tokens have the format: {id}|{plaintext_token}
let sanctum_token = "1|abc123def456...";
let response = client.authorize_gateway(
sanctum_token,
"gateway-123",
None,
None
).await?;
// Save machine token securely (automatic storage selection)
let instance_id = "my-gateway"; // Unique identifier for this instance
let machine_token = MachineToken::new(
response.machine_token,
response.expires_at,
response.gateway.id,
response.gateway.code,
response.abilities,
);
save_token(instance_id, &machine_token).await?;
Ok(())
}The SDK supports two authentication methods:
JWT tokens are validated locally using RS256 signature verification with JWKS endpoint discovery.
Use JWT tokens when:
- You need local token validation before making API calls
- You need to extract claims (user info, team info) from the token
- You're working with existing JWT-based infrastructure
- You want to verify token authenticity without server roundtrips
Authorization Flow:
- CLI sends user JWT token to Harmony Management API
- Harmony validates JWT locally (signature verification via JWKS)
- Harmony exchanges user JWT for machine token from Runbeam Cloud
- Runbeam Cloud issues machine-scoped token (30-day expiry)
- Machine token is stored securely for autonomous API access
Sanctum tokens (format: {id}|{token}) are passed directly to the server for validation.
Use Sanctum tokens when:
- You want simpler authentication without local validation complexity
- Your application doesn't need to inspect token claims locally
- You're integrating with Laravel-based authentication systems
- You prefer server-side token validation
Authorization Flow:
- CLI sends user Sanctum API token to Harmony Management API
- Harmony passes token directly to Runbeam Cloud (no local validation)
- Runbeam Cloud validates token and issues machine-scoped token (30-day expiry)
- Machine token is stored securely for autonomous API access
Note: All API methods accept both JWT and Sanctum tokens interchangeably.
The SDK automatically manages secure token storage with no configuration required.
When you call save_token(), load_token(), or clear_token(), the SDK automatically:
- Tries OS Keyring first (macOS Keychain, Linux Secret Service, Windows Credential Manager)
- Falls back to Encrypted Filesystem if keyring unavailable (headless/CI/CD environments)
Each instance gets its own isolated storage using an instance_id:
use runbeam_sdk::{save_token, load_token, clear_token, MachineToken};
// Each instance_id gets separate storage at ~/.runbeam/<instance_id>/
let instance_id = "harmony-production";
// Save token
save_token(instance_id, &token).await?;
// Load token
if let Some(token) = load_token(instance_id).await? {
println!("Loaded token for gateway: {}", token.gateway_code);
}
// Clear token
clear_token(instance_id).await?;When using encrypted filesystem storage (fallback), keys are sourced from:
-
RUNBEAM_ENCRYPTION_KEYenvironment variable (production/containers)export RUNBEAM_ENCRYPTION_KEY=$(age-keygen | base64 -w 0)
-
Auto-generated key at
~/.runbeam/<instance_id>/encryption.key(development)- Created with restrictive permissions (0600 on Unix)
- Persists across application restarts
✅ Tokens are NEVER stored unencrypted on disk ✅ Automatic keyring use when available ✅ age X25519 encryption for filesystem storage ✅ Instance isolation - multiple instances can coexist ✅ Thread-safe for concurrent access
cargo build
cargo build --releasecargo test # Run all tests
cargo test --lib # Run only library testscargo clippy
cargo clippy -- -D warningscargo doc --openAll API methods accept JWT tokens, Sanctum tokens, or machine tokens for authentication.
use runbeam_sdk::RunbeamClient;
#[tokio::main]
async fn main() -> Result<(), Box<dyn std::error::Error>> {
let client = RunbeamClient::new("https://runbeam.example.com");
// Works with JWT tokens, Sanctum tokens, or machine tokens
let token = "your_token_here";
// List all gateways
let gateways = client.list_gateways(token).await?;
for gateway in gateways.data {
println!("Gateway: {} ({})", gateway.name, gateway.code);
}
// Get specific gateway
let gateway = client.get_gateway(token, "gateway-123").await?;
println!("Gateway enabled: {}", gateway.data.enabled);
Ok(())
}use runbeam_sdk::RunbeamClient;
#[tokio::main]
async fn main() -> Result<(), Box<dyn std::error::Error>> {
let client = RunbeamClient::new("https://runbeam.example.com");
let token = "your_token_here";
// List all services
let services = client.list_services(token).await?;
for service in services.data {
println!("Service: {} on gateway {}", service.name, service.gateway_id);
}
// Get specific service
let service = client.get_service(token, "service-456").await?;
println!("Service type: {}", service.data.service_type);
Ok(())
}use runbeam_sdk::RunbeamClient;
#[tokio::main]
async fn main() -> Result<(), Box<dyn std::error::Error>> {
let client = RunbeamClient::new("https://runbeam.example.com");
let token = "your_token_here";
// Fetch all configuration resources
let endpoints = client.list_endpoints(token).await?;
let backends = client.list_backends(token).await?;
let pipelines = client.list_pipelines(token).await?;
// Use the data to configure harmony-proxy
println!("Endpoints: {}", endpoints.data.len());
println!("Backends: {}", backends.data.len());
println!("Pipelines: {}", pipelines.data.len());
Ok(())
}runbeam_api/client.rs- HTTP client for Runbeam Cloud APIrunbeam_api/jwt.rs- JWT validation with JWKS cachingrunbeam_api/resources.rs- API resource types (Gateway, Service, etc.)runbeam_api/token_storage.rs- Token persistence operationsrunbeam_api/types.rs- Error types and API structuresstorage/mod.rs- Storage backend trait and implementations
Part of the Runbeam project.