Context
0207 decision 2 sends every machine identity through ZITADEL, and 0087 decision 5 said tokens are shown once, stored hashed, scoped and revocable. Neither says who issues an API key, how it is rotated, recognised when leaked, or seen in use. The owner’s answers of 2026-10-21 (screenshot gap review, item 9, and the issuer decision that followed the PR review) set the issuer and the whole lifecycle.Decision
- Stackra issues API keys.
@figentra/service-identityissues API keys for programmatic access by developers and integrations. - Each key maps to a ZITADEL machine identity. The gateway (0237) validates the key and maps it to a ZITADEL machine identity. The machine identity is the principal; its permissions are its IAM grants (0208), decided by the policy decision point (0209). ZITADEL stays the issuer for sign-in, OIDC and machine-to-machine JWTs.
- Shown once, stored hashed. The secret is shown once at creation and stored only as a hash.
- Prefix registered with GitHub secret scanning. Every key starts with a recognisable prefix registered with GitHub secret scanning.
- Checksum suffix. The key ends with a CRC32 checksum (as GitHub’s suffix does). It catches typos and malformed keys, so a scanner and the gateway reject them without a database lookup. It does not prove a key is authentic; only the hash lookup does.
- Tenant tokens are bound to one tenant. A tenant service token works only in the tenant it was issued for.
- Scopes. A key carries scopes, and the gateway checks each call against them.
- Last used. The key list shows each key’s last-used time and IP address.
- Rotation with overlap. Rotating a key issues a new one; old and new both work during an overlap window, then the old one stops.
- Expiry. A key has an expiry.
- Revoke, and auto-revoke on a scanning report. A key can be revoked at once. A key reported by GitHub secret scanning is revoked automatically and its owner is notified.
- Example usage. Each key’s page shows an example usage snippet for that key’s scopes.
Consequences
- A leaked key is revoked when GitHub reports it, not found by the customer weeks later.
- The key is a credential, not a second permission model: the machine identity is the principal, its permissions are its IAM grants (0208), and the policy decision point (0209) decides each call.
- service-identity owns key issuance, hashing, the checksum format and the secret-scanning endpoint.
- Rotation does not need a deploy at the exact moment the old key dies, because of the overlap window.
- Last-used data is written on calls, so its write path must stay cheap (sampled or batched).
Enforcement
planned — a storage test asserts no plaintext key is persisted; a gateway test rejects a bad checksum before lookup, refuses a tenant token in another tenant, accepts both keys inside the overlap window and only the new one after it, and refuses expired and revoked keys; a test of the secret-scanning endpoint asserts a reported key is revoked.Open details
The owner did not give these; the conservative default below applies until an ADR changes it.- Prefix.
<product>_<env>_followed by the secret and the checksum, for examplestk_live_andstk_test_; the exact strings are fixed when the GitHub secret-scanning partnership is filed. - Checksum. CRC32 of the secret, base62-encoded, as the last 6 characters.
- Overlap window. 24 hours by default, settable up to 7 days.
- Expiry. Required at creation, 90 days by default, at most 1 year.
- Last-used IP retention. Follows the access-log retention of 0212.