JWKS & Key Rotation
ES256 signing key management, the JWKS endpoint, and zero-downtime key rotation.
Atom signs JWTs using ES256 (ECDSA over P-256 with SHA-256) and publishes its public keys at a standard JWKS endpoint. This allows external services to verify tokens independently and enables zero-downtime key rotation.
Why ES256
Atom uses asymmetric signing rather than HMAC-SHA256 (HS256) because:
- No shared secret — external verifiers only need the public key, not the signing secret.
- Separation of concerns — a service can verify who issued a token without being able to forge tokens.
- Standard ecosystem — JWKS/ES256 is supported by every major JWT library and API gateway.
JWKS endpoint
No authentication required. Returns both the primary and standby public keys:
The response always includes both the primary (current signing key) and standby (previous key, still valid). Retired keys are never published.
Key lifecycle
At any point in time:
- Primary — all new tokens are signed with this key's
kid. - Standby — tokens issued before the last rotation are still valid under this key.
- Retired — any rotation beyond the first promotes the old standby to retired. Retired keys are kept in the database for audit but removed from JWKS. Tokens referencing a retired
kidare rejected.
Key rotation
Rotation requires a permission block that allows manage on signing keys or platform management scope.
The rotation is:
- Transactional — retire standby, demote primary to standby, insert new primary in a single DB transaction.
- Instantaneous — the in-process key store (
Arc<RwLock<ActiveKeys>>) is updated immediately. All subsequent token signatures use the new primary key. No restart required. - Zero-downtime — tokens signed with the old primary key remain valid under the standby key until they expire (default 1 hour). After one JWT TTL, the standby key covers no outstanding tokens.
Rotation sequence
After one JWT TTL (default 1h), all outstanding tokens reference either K3 or K2. K1-signed tokens have expired and no tokens reference the retired key.
External verification
To verify Atom JWTs in an external service, fetch the JWKS and cache the keys. Re-fetch when you encounter an unknown kid.
Node.js example (using jose)
The jose library handles kid lookup, caching, and automatic re-fetch on unknown key IDs automatically.
Python example (using python-jose)
External JWT verification confirms the token signature and expiry, but does not check session revocation. For full authorization semantics — including revocation and policy evaluation — use POST /authz/check.
Bootstrap
On first boot, Atom automatically generates the initial primary ES256 key pair and stores it in the signing_keys table. No manual key material configuration is required.
Private keys are stored as PKCS8 PEM in the database. In production deployments, encrypt the private_key column at rest or delegate key storage to a KMS and store only references.