rdev/docs/api/authentication.md
jordan 72d16929ca feat: Implement hexagonal architecture with services, webhooks, queue, and telemetry
Major refactoring to hexagonal (ports & adapters) architecture:

- Add service layer (apikey_service, project_service) for business logic
- Add webhook system with dispatcher and delivery tracking
- Add command queue with priority-based processing
- Add rate limiting with sliding window algorithm
- Add audit logging for command execution
- Add OpenTelemetry integration (traces, metrics, spans)
- Add circuit breaker for fault tolerance
- Add cached repository wrapper for performance
- Add comprehensive validation package
- Add Kubernetes client integration for pod management
- Add database migrations (allowed_ips, audit_log, rate_limiting, queue, webhooks)
- Add network policy and PodDisruptionBudget for k8s
- Remove legacy executor and projects/registry packages
- Untrack secrets.yaml (now managed via envault)
- Add coverage.out to .gitignore
- Add e2e test infrastructure with docker-compose
- Add comprehensive documentation (API, architecture, operations, plans)
- Add golangci-lint config and pre-commit hook

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2026-01-25 19:57:46 -07:00

4.5 KiB

Authentication Guide

rdev uses API keys for authentication. This guide covers how to authenticate requests and manage API keys.

API Key Format

API keys follow this format:

rdev_<32 random characters>

Example:

rdev_a1b2c3d4e5f6g7h8i9j0k1l2m3n4o5p6

Authenticating Requests

Using X-API-Key Header

curl https://rdev.example.com/projects \
  -H "X-API-Key: rdev_a1b2c3d4e5f6g7h8i9j0k1l2m3n4o5p6"

Using Authorization Header

curl https://rdev.example.com/projects \
  -H "Authorization: Bearer rdev_a1b2c3d4e5f6g7h8i9j0k1l2m3n4o5p6"

Scopes

API keys have scopes that limit what actions they can perform:

Scope Description
projects:read List and view projects
projects:execute Execute commands in projects
keys:read List API keys
keys:write Create and revoke API keys
admin Full access to all operations

Scope Inheritance

  • admin scope includes all other scopes
  • Command execution requires projects:execute
  • Reading projects requires projects:read or projects:execute

Managing API Keys

List Keys

curl https://rdev.example.com/keys \
  -H "X-API-Key: your-admin-key"

Response:

{
  "data": [
    {
      "id": "key-001",
      "name": "production-key",
      "key_prefix": "rdev_a1b2",
      "scopes": ["projects:read", "projects:execute"],
      "created_at": "2024-01-01T00:00:00Z",
      "last_used_at": "2024-01-15T10:30:00Z"
    }
  ]
}

Create Key

curl -X POST https://rdev.example.com/keys \
  -H "X-API-Key: your-admin-key" \
  -H "Content-Type: application/json" \
  -d '{
    "name": "ci-pipeline",
    "scopes": ["projects:execute"],
    "expires_in": "30d",
    "allowed_ips": ["10.0.0.0/8"]
  }'

Request body:

{
  "name": "ci-pipeline",
  "scopes": ["projects:read", "projects:execute"],
  "expires_in": "30d",
  "allowed_ips": ["10.0.0.0/8", "192.168.1.0/24"]
}
Field Type Required Description
name string yes Human-readable key name
scopes array yes Permission scopes
expires_in string no Expiration duration (e.g., "30d", "24h")
allowed_ips array no IP allowlist in CIDR notation

Response:

{
  "data": {
    "id": "key-002",
    "name": "ci-pipeline",
    "key": "rdev_x1y2z3...",
    "scopes": ["projects:execute"],
    "created_at": "2024-01-15T10:30:00Z",
    "expires_at": "2024-02-14T10:30:00Z"
  }
}

Important

: The full key is only returned once at creation time. Store it securely!

Revoke Key

curl -X DELETE https://rdev.example.com/keys/key-002 \
  -H "X-API-Key: your-admin-key"

IP Allowlisting

Keys can be restricted to specific IP addresses:

{
  "name": "restricted-key",
  "scopes": ["projects:execute"],
  "allowed_ips": [
    "10.0.0.0/8",
    "192.168.1.100/32"
  ]
}

If allowed_ips is empty or not set, all IPs are allowed.

Key Expiration

Keys can have an expiration time:

  • Set at creation with expires_in
  • Cannot be extended after creation
  • Expired keys return KEY_EXPIRED error

Best Practices

1. Use Least Privilege

Create keys with only the scopes needed:

{
  "name": "read-only-dashboard",
  "scopes": ["projects:read"]
}

2. Set Expiration

For temporary access, set expiration:

{
  "name": "contractor-access",
  "scopes": ["projects:execute"],
  "expires_in": "7d"
}

3. Use IP Restrictions

For CI/CD pipelines with known IPs:

{
  "name": "github-actions",
  "scopes": ["projects:execute"],
  "allowed_ips": ["192.30.252.0/22"]
}

4. Rotate Keys Regularly

Create new keys and revoke old ones periodically.

5. Use Descriptive Names

Name keys by their purpose:

  • ci-github-actions
  • dev-jordan-laptop
  • prod-monitoring

Error Responses

401 Unauthorized

Missing or invalid API key:

{
  "error": {
    "code": "UNAUTHORIZED",
    "message": "Missing API key"
  }
}

401 Key Revoked

{
  "error": {
    "code": "KEY_REVOKED",
    "message": "API key has been revoked"
  }
}

401 Key Expired

{
  "error": {
    "code": "KEY_EXPIRED",
    "message": "API key has expired"
  }
}

403 IP Not Allowed

{
  "error": {
    "code": "IP_NOT_ALLOWED",
    "message": "IP address not allowed for this API key"
  }
}

403 Forbidden

Insufficient scopes:

{
  "error": {
    "code": "FORBIDDEN",
    "message": "Insufficient permissions. Required: projects:execute"
  }
}