//Organization Signing Keys

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 |