Managing apps & key rotation
As tenant-admin, register and manage the app/publisher credentials backend services use to emit events (see Apps & credentials).
Register an app
curl -s -X POST "$CNS_API/admin/v1/apps" \
-H "Authorization: Bearer $ADMIN_TOKEN" -H "Content-Type: application/json" \
-d '{
"app_id": "billing-svc",
"name": "Billing Service",
"allowed_event_types": ["invoice.paid", "invoice.voided"]
}'
201 with the new app record, including a freshly materialized ed25519 keypair
(private key in the secrets adapter; key_version: 1, public key returned as
public_key_base64). 409 if app_id is already registered — app ids are global,
not per-tenant, since an id resolves one secrets-adapter keypair path.
Leave allowed_event_types empty (or omit it) to let this app emit any event
type for its tenant.
Rotate its keys
curl -s -X POST "$CNS_API/admin/v1/apps/billing-svc/rotate-keys" -H "Authorization: Bearer $ADMIN_TOKEN"
Returns the app with a new key_version/public_key_base64. The old key stays
valid for verification until any already-issued service-JWT signed with it expires
naturally — there's no hard cutover, which is why service-JWT TTLs should stay short
(minutes, not days): that TTL is what bounds the rotation-overlap window.
Check its current public key
curl -s -H "Authorization: Bearer $ADMIN_TOKEN" "$CNS_API/admin/v1/apps/billing-svc/public-key"
# -> {"app_id":"billing-svc","key_version":2,"public_key_base64":"..."}
key_version/public_key_base64 are live reads from the secrets adapter at
request time — never cached in the app registry record — so a transient secrets-
adapter outage degrades these two fields to their zero value rather than failing the
whole request.
Update its allow-list
curl -s -X PATCH "$CNS_API/admin/v1/apps/billing-svc" \
-H "Authorization: Bearer $ADMIN_TOKEN" -H "Content-Type: application/json" \
-d '{ "allowed_event_types": ["invoice.paid", "invoice.voided", "invoice.refunded"] }'
Omitting allowed_event_types on a PATCH leaves it unchanged; an empty array
explicitly clears the restriction (any event type allowed).
Deregister it
curl -s -X DELETE "$CNS_API/admin/v1/apps/billing-svc" -H "Authorization: Bearer $ADMIN_TOKEN"
204. This immediately denies any further POST /v1/events as this app
(publish-authz is deregistered at once — the same policy instance the ingestor
checks). It does not delete the app's key material from the secrets adapter — an
operator has to revoke that at the source. This is a documented Phase-1 gap, not an
oversight: budget for it if "delete an app" needs to mean "and destroy its keys" in
your deployment.
Every mutation above is recorded to the tenant's audit log automatically (actor is
always the authenticated caller) — see
API Reference → Audit log.