signingKey
The gate’s Better Auth secret, persisted in AppKit’s cache.
The key decides whether a session COOKIE still verifies, so it must OUTLIVE the
process: a per-process randomBytes(32) would invalidate every outstanding cookie
on restart and make each signed-in user request a new code - painful for a tunnel,
which restarts whenever the app it wraps does. So the key is stored in the cache
AppKit already configured (memory, or Lakebase when the host wires a persistent
CacheStorage), and with persistent storage a restart keeps sessions alive for
KEY_TTL_SECONDS.
An explicitly configured TUNNEL_AUTH_JWT_SECRET still wins outright. That is
the right answer for a fleet: an operator-held secret needs no shared cache and
no convergence, and it survives a cache flush.
get / generate / get
Section titled “get / generate / get”Two instances booting at once both miss, so both would generate - and the loser
would sign cookies with a key the winner rejects. Resolution is a re-READ after
the write: whatever the cache holds afterwards is the key everyone adopts, so
the instances converge on ONE value instead of trusting the one they minted.
(set is not conditional in the cache API - there is no setnx to lean on -
and this runs once per process, so the extra round-trip is free.)
A pathological interleave can still cost a key: if A writes between B’s write
and B’s re-read, B adopts A’s key while A adopts its own. The cost is bounded -
a cookie minted in that window fails to verify and the holder signs in again -
and it cannot produce a key one instance TRUSTS but another rejects for longer
than the window itself. Set TUNNEL_AUTH_JWT_SECRET to remove the race
entirely.
Forcing every session to end
Section titled “Forcing every session to end”resolveSessionCutoff reads a date from TUNNEL_AUTH_SESSION_CUTOFF (or
--session-cutoff), and that date is part of the cache KEY. Moving it forward
makes every prior key unreachable, so every cookie signed against it stops
verifying - the log-everyone-out switch, without having to find and flush a
cache entry. The cutoff is also asserted against each token’s iat, so a
cookie that predates it is refused even if it was signed with the key that is
somehow still current.