Device Bound Session Credentials

IETF draft-ietf-oauth-attestation-based-client-auth + Chrome's DBSC proposal — binds an HTTP session to a browser-generated key pair so a stolen session cookie alone can't impersonate the user from a different device. The browser holds the private key in secure hardware; every refresh proves possession via a signed challenge.

Server flow: 1. b.dbsc.challenge() — mint a random challenge, sign it with the operator's HMAC key for replay defense, return the challenge string + the Sec-Session-Challenge header value. The browser auto-resolves the challenge via the DBSC refresh endpoint. 2. b.dbsc.verifyBindingAssertion(jwt, { challenge, expectedAud }) — verify the browser-supplied JWT signed by the binding public key. Returns { valid, sub, jkt } where jkt is the JWK thumbprint of the binding key.

Composes existing b.crypto + b.auth.jwt; DBSC mandates ES256 / RS256 (browser TPM hardware). The framework refuses HS256 / none on parsed JWTs.

b.dbsc.challenge(opts) #

stable0.10.16
{
  secretKey:    Buffer,     // operator HMAC secret (>=32 bytes)
  ttlMs:        number,     // default 5 minutes
  nonce:        string,     // optional caller-supplied nonce (default: 32-byte random)
}

Mint a fresh DBSC challenge. Returns { challenge, expiresAt, headerValue } where headerValue is the Sec-Session-Challenge value to set on the response. The challenge is HMAC-SHA3-512 signed so the server can verify the same challenge it issued on the assertion-verify path without persisting it.

var c = b.dbsc.challenge({ secretKey: opSecret });
res.setHeader("Sec-Session-Challenge", c.headerValue);

b.dbsc.verifyChallenge(challengeStr, { secretKey }) #

stable0.10.16

Verify a challenge string previously issued by challenge(). Returns truthy when the HMAC matches and the challenge hasn't expired. Refuses with typed errors on shape / expiry / MAC mismatch.

var ok = b.dbsc.verifyChallenge(req.headers["sec-session-challenge"],
  { secretKey: process.env.DBSC_HMAC_KEY });

b.dbsc.verifyBindingAssertion(assertion, opts) #

stable0.10.16
{
  secretKey:     Buffer,     // HMAC secret used by challenge() (for re-verify)
  expectedAud:   string,     // expected RP origin
  maxAgeSec:     number,     // default 300s
}

Verify a DBSC binding-assertion JWT. The browser signs a JWT with the device-bound private key whose header includes the JWK thumbprint of the binding key. Returns { valid, jkt, claims }. Refuses HS256 / none (algorithm-confusion class) and any mismatched audience / challenge.

var v = b.dbsc.verifyBindingAssertion(req.body, {
  secretKey:   opSecret,
  expectedAud: "https://rp.example",
});
if (!v.valid) throw 401;
v.jkt;   // → JWK thumbprint of the binding key (use as a session pin)

Last updated 2026-08-08T16:39:49.652Z by seeder.