Authentication

What you'll accomplish: Set up API key authentication or OIDC/SSO for your Hoziron deployment.

Authentication modes

Hoziron supports three modes, configured via [auth].mode:

ModeUse case
disabled (default)Local dev, single-user deployments
localAPI key-based auth with RBAC
oidcEnterprise SSO (Azure AD, Keycloak, Okta, Auth0)

Local API key authentication

Enable

[auth]
mode = "local"

[auth.rate_limit]
base_backoff_secs = 1
max_backoff_secs = 300
max_failed_attempts = 10

Create your first key

When no keys exist yet, the first POST /auth/keys request is allowed without authentication (bootstrap bypass):

hoziron auth create-key --role admin --name "platform-admin"

The key is shown once — save it securely. Format: hzk_Ab3xYz...

Manage keys

hoziron auth create-key --role operator --name "ci-bot" --expires-in 90d
hoziron auth list-keys
hoziron auth revoke-key <key-id>
hoziron auth rotate-key <key-id>

How it works

Key security details:

  • Keys are 32 bytes of cryptographic randomness, base64url-encoded with hzk_ prefix
  • Only argon2id hashes are stored — the raw key is never persisted
  • Validation uses constant-time comparison across all keys (prevents timing attacks)
  • The last admin key cannot be revoked (prevents lockout)

OIDC / SSO configuration

For enterprise SSO with Azure AD, Keycloak, Okta, or Auth0:

[auth]
mode = "oidc"
allow_local_service_keys = true   # API keys alongside OIDC for CI/CD

[auth.oidc]
issuer = "https://login.microsoftonline.com/{tenant}/v2.0"
audience = "api://hoziron-platform"
jwks_uri = ""                      # Auto-discovered if blank
role_claim = "roles"               # Supports dot-path: "realm_access.roles"
allowed_algorithms = ["RS256", "ES256"]
jwks_cache_ttl_secs = 3600

[auth.oidc.role_mapping]
"HozironAdmins" = "admin"
"PlatformOps" = "operator"
"Developers" = "developer"
"ReadOnly" = "viewer"

Role mapping

The role_claim field supports dot-path traversal for nested claims (Keycloak pattern):

role_claim = "realm_access.roles"

When multiple IdP roles match, highest-privilege wins (admin > operator > developer > viewer > service).

Hybrid mode

With allow_local_service_keys = true, OIDC falls back to local API key validation when JWT validation fails. This enables:

  • CI/CD pipelines using API keys alongside human SSO
  • Break-glass access for emergencies

Brute force protection

Per-IP exponential backoff on failed attempts:

ParameterDefaultConfig key
Base backoff1 secondauth.rate_limit.base_backoff_secs
Max backoff300 seconds (5 min)auth.rate_limit.max_backoff_secs
Max failures tracked10auth.rate_limit.max_failed_attempts

Rate limit state is in-memory, per-IP, cleared on successful auth.

Endpoints always accessible

Regardless of auth configuration:

EndpointReason
GET /healthOrchestrator probes must always work
GET /metricsPrometheus scraping
POST /auth/keys (first key only)Bootstrap — create first key

Next steps


Related: