The server cannot sign for you
The backend builds signing_input — header and claims, exactly as OIDC requires —
and hands it to the browser. The HEM signs it. The backend verifies the signature and
assembles the token. There is no code path in which it produces one, and no configuration
that adds one.
Structural, not a policy setting
A database breach exposes nothing usable
No passwords, no hashes, no session secrets, no MFA seeds, no private keys. What is stored
per user is a public key, a device certificate and display claims — public by definition,
and useless without the hardware that holds the other half.
Redis only · no SQL, no credential store
No login without the physical device
Every authentication ends at a hardware module that has to answer — approved on your phone
or unlocked with a passphrase. A compromised server can refuse a login. It cannot grant one.
Pending session 120 s · auth code 60 s · PKCE S256
Standard OIDC, no cloud dependency
Discovery, JWKS, UserInfo, RP-initiated logout, PKCE — a relying party integrates the way it
integrates anything else. Nothing phones home: the only outbound call in normal operation is
to your own HEM, on your own network.
Runs air-gapped · Node.js 22 + Redis