Skip to content

Keys & their lifetimes

A cluster has few long-lived secrets, and most of its keys die with the process that made them. This page lists them all, shortest-lived first.

Key Made by Lives Replaced
Sealed-session keys Noise NK handshake (a node to a peer: IK), both sides’ ephemeral keys 1 hour at most; 10 minutes idle The client opens a new session
Transport key (X25519) Each node, in memory, at start Until the process stops On restart; clients get stale_transport_key and attest again
Receipt key (Ed25519) Each node, on its first start; kept in its data directory wrapped under K_r; signs receipts and the sessions the node issues As long as the node’s data directory When a node is replaced (a new data directory): verify_app_cluster returns the new key, and the node’s sessions refresh
Session token The node that signs someone in, with its receipt key 15 minutes Exchanged with a refresh token
Refresh token (rt_…) The same node; only its hash is stored 30 days The first refresh once it is an hour old returns a new one; younger, it is kept and nothing is logged
Operator key (Ed25519) The operator (mdma); only the public half is in the system state The cluster’s lifetime Not rotated yet
API key (cal_…) Generated for an account; only its hash is stored Up to 1 year (ttlSecs) Revoked by the account, or expires
Passkey The person’s authenticator Until removed from the account Added and removed by the account (at least one stays)
Storage key K_r HKDF of the KMS key and the cluster name One mero-tee release (each has its own mero-kms) Replaced with the release; it only wraps K_c
Cluster key K_c The founding node’s K_r; handed to new nodes by attestation The cluster’s lifetime Not rotated

Sessions are signed by the node that issued them

Section titled “Sessions are signed by the node that issued them”

Each node signs the sessions it issues with its own receipt key (Sessions); no session-signing key is shared or replicated. Every node attests each peer’s receipt key at its registered address ahead of time and verifies tokens from that, so a node’s sessions survive its restart (same key) and outlive it while it is down or frozen. They stop verifying when the node is removed, or replaced on a new data directory (a new key): clients refresh (Failover).

Revocations are system commands, so they hold on every node once applied, and because a credential is judged on fresh system state, they hold before the next request anywhere.

Event What ends
POST /auth/logout This session: its refresh tokens go, its tokens stop verifying
POST /auth/logout-all Every session of the account
Removing a passkey Every session opened with that passkey; tokens of a session whose passkey is gone are also refused directly
A refresh token presented again after it was exchanged Its session (RefreshReused): someone else holds a copy
Revoking an API key That key, at once

A revoked session id is remembered for an hour (REVOKED_SESSION_KEEP_SECS), past the life of any token it could have minted, and then forgotten; exchanged refresh tokens are forgotten once they would have expired.

A passkey assertion reports a signature counter. SetSignCount accepts only a counter that moves forward, whatever order sign-ins committed in, so a cloned authenticator replaying an old counter is refused; an authenticator that reports zero every time records nothing. It carries the assertion that reached the counter and is checked at apply, so no node can set a counter the authenticator never reached.

  • K_c is fixed for the cluster. K_r changes with every release, but it only wraps K_c (The cluster key). Rotating K_c would mean re-sealing every value and snapshot; nothing does that today. Keys per app are not done.
  • A rollback counter — something that would let a node notice it was restarted on an older copy of its disk — is not done.