Update the signing key policy
PATCH /v1/signing-keys/policy · permission signing-keys:write
Updates the signing key policy with a JSON merge patch (application/merge-patch+json, RFC 7396). If-Match is required: missing gives 428, a stale version gives 412. If the policy was never written the version is "0". A patch that changes nothing writes nothing and keeps the version.
Changing algorithm generates a new next key with the new algorithm right away; it can become active at the earliest 7 days later, so verifiers that cache the JWKS see it first (an earlier immediate rotation fails with 409 next_key_too_young). The active key keeps signing until then. Changing rotation_interval_days moves next_rotation_at. A successful change writes the signing_key.policy_updated management audit record.
Request
| Field | Type | Required | Description |
|---|---|---|---|
If-Match |
header | yes | The ETag of the policy as last read ("0" if never written). Missing: 428; stale: 412. |
algorithm |
string | no | RS256, ES256, PS256 or EdDSA. Cannot be null. |
rotation_interval_days |
integer | no | 30-365. Cannot be null. |
storage |
string | no | wrapped (the private key is stored encrypted under the environment key and used only inside the signing service). transit (key held in the key management service) is not available yet and is rejected with 422. Cannot be null. |
Response
200 OK with the updated policy and the new ETag.
{
"algorithm": "ES256",
"rotation_interval_days": 90,
"storage": "wrapped",
"next_rotation_at": "2026-12-04T09:30:00.123456Z",
"updated_at": "2026-10-05T09:30:00.123456Z"
}
Errors
| HTTP | code | When |
|---|---|---|
| 400 | unknown_field |
The patch contains an unknown or read-only field, or is not a JSON object (malformed_request). |
| 412 | precondition_failed |
If-Match does not match the current version. |
| 415 | unsupported_media_type |
The content type is not application/merge-patch+json. |
| 422 | validation_failed |
A value is invalid (invalid_value), out of range (out_of_range), set to null (invalid), or storage is transit. |
| 428 | precondition_required |
The If-Match header is missing. |
| 401 | unauthenticated |
The credential is missing, invalid or revoked. |
| 403 | insufficient_permissions |
The credential lacks the required permission. |
| 429 | rate_limited |
The rate limit was exceeded; retry after the Retry-After period. |
| 501 | not_implemented |
The operation is not available in this deployment yet; retrying does not change the result. |
| 503 | service_unavailable |
A dependency is temporarily unavailable; retry after the Retry-After period. |
Example
curl -X PATCH https://api.eu.keenauth.com/v1/signing-keys/policy \
-H "Authorization: Bearer $KEENAUTH_SECRET_KEY" \
-H "Content-Type: application/merge-patch+json" \
-H 'If-Match: "0"' \
-d '{"algorithm":"ES256","rotation_interval_days":90}'