demo · v142
Protocol Handshake
Step through the actual DBSC HTTP/JWS dance from the IETF draft: server says Sec-Session-Registration, client generates a TPM-backed keypair and POSTs a signed registration JWT, server returns a short-lived cookie plus the refresh URL, browser auto-renews by signing the server's nonce. This is the bit that's hard to picture from prose — the steps below run the exchange against a mocked server in your tab.
chrome://flags/#enable-device-bound-session-credentials and serve over HTTPS. This page runs a pure-JS
mock of the protocol so the handshake is observable without a real server or TPM.
-
server → client
Sign-in response includes header
The server sets a short-lived auth cookie and tells the browser to start a device-bound session.
HTTP/2 200 OK Set-Cookie: auth_session=abc…; Max-Age=600; Secure; HttpOnly Sec-Session-Registration: (RS256 ES256);path="/StartSession";challenge="cha_001" -
browser → TPM
Generate device-bound keypair
Chrome asks the OS to create a non-extractable keypair inside the TPM / Secure Enclave. The private key never leaves hardware.
// pseudo-internal const kp = await deviceTpm.generate({ alg: "ES256", extractable: false }); -
client → server
POST signed registration JWT to /StartSession
Body is a JWS proving possession of the new private key and echoing the server's challenge.
POST /StartSession Content-Type: application/jwt eyJ0eXAiOiJzZXNz…Y2hhX18wMDEi ← header.payload.signature { "iat": 1730…, "aud": "https://app.example", "jti": "cha_001", "key": { "kty":"EC","crv":"P-256","x":"…","y":"…" } } -
server → client
Session config + first refresh cookie
Server confirms the binding, returns the JSON session config and a refresh cookie tagged with the session ID.
HTTP/2 200 OK Set-Cookie: auth_session=xyz…; Max-Age=600 Content-Type: application/json { "session_identifier":"sess_42", "refresh_url":"/RefreshSession", "scope":{"include_site":true}, "credentials":[{"name":"auth_session","attributes":"Secure;HttpOnly"}] } -
client → server
10 minutes later: auth_session expired, auto-refresh
Browser intercepts the would-be request, fetches /RefreshSession with a fresh signed JWT proving the same TPM key.
POST /RefreshSession Sec-Session-Id: sess_42 Content-Type: application/jwt eyJhbGciOiJFUzI1Ni… ← signed with the same device key -
server → client
Refresh succeeds, new short-lived cookie issued
Server validates the JWS against the registered public key, mints a fresh
auth_sessioncookie. An attacker who exfiltrated the old cookie can't refresh — they don't have the TPM key.HTTP/2 200 OK Set-Cookie: auth_session=def…; Max-Age=600; Secure; HttpOnly
DBSC's whole value is steps 4–5: the server bound the auth cookie to a TPM key on step 2, so any exfiltrated cookie can only buy the attacker minutes before the next refresh fails on their machine.
see also
- DBSC — feature index
- Attacker scenarios demo
- ChromeStatus entry
- DBSC draft spec