Authentication
Secure your Rustberg deployment with multiple authentication methods.
Table of contents
- Overview
- API Key Authentication
- JWT Authentication
- Chain Authentication
- Rate Limiting
- Security Best Practices
- Audit Logging
- Troubleshooting
- Next Steps
Overview
Rustberg supports multiple authentication mechanisms:
| Method | Use Case | Production Ready |
|---|---|---|
| API Keys | Service-to-service, CI/CD | ✅ Recommended |
| JWT/OIDC | User authentication, SSO | ✅ Ready |
| Chain Auth | JWT with API Key fallback | ✅ Ready |
All authentication is required by default. Anonymous access must be explicitly enabled (not recommended).
API Key Authentication
How It Works
- Server generates API key with cryptographically secure random bytes
- Key is hashed using Argon2id (PHC winner, OWASP recommended)
- Client includes key in
Authorization: Bearer <key>header - Server verifies using constant-time comparison
Security Properties
| Property | Implementation |
|---|---|
| Hashing | Argon2id (19 MiB memory, 2 iterations) |
| Timing | Constant-time verification |
| Storage | Prefix-indexed, PHC format hash |
| Leakage | Dummy hash prevents user enumeration |
Creating API Keys
Programmatic (Recommended)
use rustberg::auth::ApiKeyStore;
// Create store (in-memory or persistent)
let store = ApiKeyStore::new();
// Generate new API key
let (key_id, plaintext) = store.create_key(
"spark-etl", // name
Some("tenant-123"), // tenant_id
vec!["data-writer"], // roles
).await?;
// plaintext = "rustberg_xxxxxxxxxxxxxxxxxxxxxxxxxxxxx"
// Store this securely! It cannot be retrieved later.
CLI Tool
# Generate API key (outputs to stdout)
./rustberg generate-key \
--name "spark-etl" \
--tenant "tenant-123" \
--roles "data-writer,data-reader"
Using API Keys
# HTTP Header
curl -H "Authorization: Bearer rustberg_xxxxx" \
http://localhost:8181/v1/namespaces
# Query parameter (not recommended)
curl "http://localhost:8181/v1/namespaces?token=rustberg_xxxxx"
Persistent API Key Storage
By default, API keys are stored in memory and lost on restart. For production:
use rustberg::App;
// Enable persistent API key storage
let (app, store) = App::builder()
.with_storage_backend("s3://bucket/catalog")
.with_encryption_key(encryption_key) // Optional: encrypt at rest
.build_with_persistent_api_key_auth_async()
.await;
Or via configuration:
[storage]
object_store_url = "s3://bucket/catalog"
[auth]
persistent_api_keys = true
encryption_key_env = "RUSTBERG_MASTER_KEY"
JWT Authentication
JWKS Configuration
Rustberg validates JWTs against a JWKS (JSON Web Key Set) endpoint:
[auth.jwt]
jwks_url = "https://auth.example.com/.well-known/jwks.json"
issuer = "https://auth.example.com"
audience = "rustberg-catalog"
Token Requirements
| Claim | Required | Description |
|---|---|---|
iss |
✅ | Must match configured issuer |
aud |
✅ | Must match configured audience |
exp |
✅ | Token expiration time |
sub |
✅ | User/service identifier |
tenant_id |
⚠️ | Required for multi-tenant |
roles |
⚠️ | Optional, for RBAC |
Example JWT Payload
{
"iss": "https://auth.example.com",
"aud": "rustberg-catalog",
"sub": "user@example.com",
"exp": 1706313600,
"tenant_id": "tenant-123",
"roles": ["data-reader", "data-writer"]
}
Provider Examples
Auth0
[auth.jwt]
jwks_url = "https://your-tenant.auth0.com/.well-known/jwks.json"
issuer = "https://your-tenant.auth0.com/"
audience = "rustberg-api"
Keycloak
[auth.jwt]
jwks_url = "https://keycloak.example.com/realms/myrealm/protocol/openid-connect/certs"
issuer = "https://keycloak.example.com/realms/myrealm"
audience = "rustberg"
Okta
[auth.jwt]
jwks_url = "https://your-org.okta.com/oauth2/default/v1/keys"
issuer = "https://your-org.okta.com/oauth2/default"
audience = "rustberg"
Chain Authentication
Chain authentication tries multiple methods in order:
- JWT - Check
Authorization: Bearer <jwt>header - API Key - Fall back to
Authorization: Bearer <api_key>
This enables:
- User authentication via SSO (JWT)
- Service accounts via API keys
- Gradual migration between methods
Configuration
[auth]
chain_auth = true
[auth.jwt]
jwks_url = "https://auth.example.com/.well-known/jwks.json"
issuer = "https://auth.example.com"
audience = "rustberg"
[auth.api_key]
enabled = true
Rate Limiting
Protect against abuse with token bucket rate limiting:
[rate_limit]
enabled = true
requests_per_second = 100
burst_size = 200
trust_proxy_headers = false # Set true behind load balancer
Per-Tenant Limits
[rate_limit]
enabled = true
default_rps = 100
[rate_limit.tenants]
"tenant-premium" = 1000
"tenant-basic" = 50
Security Best Practices
API Keys
- Never commit API keys to source control
- Rotate keys periodically (90 days recommended)
- Use separate keys per service/environment
- Monitor key usage via audit logs
JWT
- Validate all claims (iss, aud, exp)
- Use short-lived tokens (15 minutes recommended)
- Enable token refresh flows
- Monitor for unusual token patterns
TLS
Always use TLS in production. Rustberg warns when running without TLS.
# Enable TLS (recommended)
./rustberg --tls-cert /path/to/cert.pem --tls-key /path/to/key.pem
# Self-signed for development
./rustberg generate-cert --common-name localhost
./rustberg --tls-cert ./cert.pem --tls-key ./key.pem
Audit Logging
All authentication decisions are logged:
{
"timestamp": "2026-01-24T12:00:00Z",
"event": "auth_success",
"principal": "spark-etl",
"tenant_id": "tenant-123",
"method": "api_key",
"ip": "10.0.0.5",
"request_id": "abc123"
}
Failed Authentication
{
"timestamp": "2026-01-24T12:00:01Z",
"event": "auth_failure",
"reason": "invalid_token",
"method": "jwt",
"ip": "10.0.0.6",
"request_id": "def456"
}
Secrets (tokens, keys) are never logged.
Troubleshooting
“401 Unauthorized”
- Verify the API key/JWT is correct
- Check the
Authorizationheader format:Bearer <token> - Ensure the token hasn’t expired
- Verify JWKS URL is accessible
“403 Forbidden”
Authentication succeeded but authorization failed:
- Check tenant isolation (correct
tenant_id?) - Verify roles/permissions in Cedar policies
- Check audit logs for the specific denial reason
JWT Validation Failures
# Debug JWT claims
echo 'eyJhbGc...' | cut -d. -f2 | base64 -d | jq
# Test JWKS endpoint
curl https://auth.example.com/.well-known/jwks.json | jq
Next Steps
- Authorization Guide - Cedar policies, RBAC, ABAC
- Encryption Guide - Encrypt API keys at rest
- API Reference - Authentication endpoints