Skip to main content

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.