API Keys
API keys give machine clients authenticated access without a session cookie or browser flow.
How they work
Section titled “How they work”- The raw key (64-char hex string) is shown once on creation and never stored.
- Only the SHA-256 hash of the key is persisted.
- On authentication, the caller presents the raw key; authx hashes it and does a lookup.
- Each key has a 8-character prefix stored in plaintext for display purposes (
auth_a1b2c3d4…).
use authx_plugins::ApiKeyService;
let svc = ApiKeyService::new(store.clone());Create a key
Section titled “Create a key”let resp = svc.create( user_id, Some(org_id), // optional org scope "CI pipeline".into(), // human-readable name vec!["read".into(), "deploy".into()], // scopes Some(Utc::now() + chrono::Duration::days(365)), // optional expiry).await?;
// Show resp.raw_key to the user exactly onceprintln!("Save this key: {}", resp.raw_key);// resp.key contains the ApiKey model (no raw key)List keys
Section titled “List keys”let keys = svc.list(user_id).await?;// Returns Vec<ApiKey> — key_hash is included but raw key is gone foreverRevoke a key
Section titled “Revoke a key”svc.revoke(user_id, key_id).await?;// Enforces ownership — user_id must own the keyAuthenticate an incoming request
Section titled “Authenticate an incoming request”// Extract raw key from Authorization header: "Bearer <raw_key>"let key = svc.authenticate(&raw_key).await?;// Returns Err(AuthError::InvalidToken) if unknown, expired, or revoked// Updates last_used_at automatically
key.user_id // who owns this keykey.scopes // Vec<String>key.org_id // optional org contextAxum extractor pattern
Section titled “Axum extractor pattern”use axum::{extract::TypedHeader, headers::{Authorization, Bearer}};
async fn api_handler( TypedHeader(auth): TypedHeader<Authorization<Bearer>>, State(svc): State<ApiKeyService<MemoryStore>>,) -> impl IntoResponse { match svc.authenticate(auth.token()).await { Ok(key) => /* proceed */, Err(_) => StatusCode::UNAUTHORIZED.into_response(), }}