Organization Signing Keys
Per-organization asymmetric signing keys for issuing verifiable, org-scoped JWTs and signed payloads.
All endpoints require Authorization: Bearer <admin-jwt> with the admin scope.
Key Management
POST /api/admin/organizations/:org_uuid/signing-keys
Generates a new RSA-4096 or Ed25519 signing key pair for the organization.
Input: ~~~json { "algorithm": "ed25519", "description": "Primary signing key — July 2024" } ~~~
Output: ~~~json { "key_id": "key-uuid-123", "algorithm": "ed25519", "public_key": "-----BEGIN PUBLIC KEY----- ...", "created_at": "2024-07-11T10:00:00Z", "active": true } ~~~
The private key is stored in ButtrBase's HSM and is never returned. Use the /sign endpoint to sign payloads.
GET /api/admin/organizations/:org_uuid/signing-keys
Lists all signing keys for the organization.
Output: ~~~json { "data": [ { "key_id": "key-uuid-123", "algorithm": "ed25519", "active": true, "created_at": "2024-07-11T10:00:00Z" } ] } ~~~
DELETE /api/admin/organizations/:org_uuid/signing-keys/:key_id
Deletes a signing key. Cannot delete the currently active key.
Signing Payloads
POST /api/admin/organizations/:org_uuid/signing-keys/:key_id/sign
Signs an arbitrary JSON payload using the specified key.
Input: ~~~json { "payload": { "sub": "user-uuid-123", "org": "org-uuid-12345", "action": "download", "resource": "invoice_001.pdf", "exp": 1720699200 } } ~~~
Output: ~~~json { "token": "eyJ...", "key_id": "key-uuid-123", "algorithm": "ed25519" } ~~~
Key Rotation
POST /api/admin/organizations/:org_uuid/signing-keys/rotate
Generates a new key and atomically sets it as the active key. The previous key remains valid for 24 hours to allow in-flight tokens to complete.
Output: ~~~json { "new_key_id": "key-uuid-456", "previous_key_id": "key-uuid-123", "previous_key_expires_at": "2024-07-12T10:00:00Z" } ~~~
JWKS Endpoint
Public keys are exposed via a standard JWKS endpoint for token verification by third parties:
~~~ GET /api/organizations/:org_uuid/.well-known/jwks.json ~~~
Endpoint Summary
| Method | Path | Purpose |
|---|---|---|
| GET | /api/admin/organizations/{org}/signing-keys | List keys |
| POST | /api/admin/organizations/{org}/signing-keys | Generate key |
| DELETE | /api/admin/organizations/{org}/signing-keys/{id} | Delete key |
| POST | /api/admin/organizations/{org}/signing-keys/{id}/sign | Sign payload |
| POST | /api/admin/organizations/{org}/signing-keys/rotate | Rotate active key |
| GET | /api/organizations/{org}/.well-known/jwks.json | Public JWKS |
When to Use
- Issue org-scoped JWTs that downstream services can verify without calling ButtrBase
- Sign download URLs, invoices, or audit log lines for non-repudiation
Error Reference
| Status | Code | Meaning |
|--------|------|---------|
| 400 | invalid_algorithm | Unsupported key algorithm |
| 401 | unauthorized | Missing or invalid Authorization header |
| 403 | forbidden | Admin scope required |
| 404 | key_not_found | Signing key ID does not exist |
| 409 | active_key_exists | Cannot delete the currently active signing key |
| 422 | rotation_in_progress | Key rotation already underway |