Skip to content

Token Binding — Binding Tokens to Client Devices for Security

DodaTech Updated 2026-06-28 1 min read

In this tutorial, you'll learn about Token Binding. We cover key concepts, practical examples, and best practices to help you understand and apply this topic effectively.

Token binding cryptographically binds authentication tokens to a specific client, making stolen tokens unusable from other devices.

// DPoP (Demonstrating Proof of Possession) implementation
class DPoPProof {
  constructor(privateKey) {
    this.privateKey = privateKey;
  }

  async generateProof(method, url, accessToken) {
    const header = {
      typ: 'dpop+jwt',
      alg: 'ES256',
      jwk: await this.getPublicJWK()
    };

    const thumbprint = await this.calculateJWKThumbprint(header.jwk);

    const payload = {
      jti: crypto.randomUUID(),
      htm: method,
      htu: url,
      iat: Math.floor(Date.now() / 1000),
      ath: await this.hashAccessToken(accessToken)
    };

    return this.sign(header, payload);
  }

  async hashAccessToken(token) {
    const hash = await crypto.subtle.digest('SHA-256', new TextEncoder().encode(token));
    return base64url(new Uint8Array(hash));
  }

  async calculateJWKThumbprint(jwk) {
    const sorted = {
      crv: jwk.crv,
      kty: jwk.kty,
      x: jwk.x,
      y: jwk.y
    };
    const hash = await crypto.subtle.digest('SHA-256',
      new TextEncoder().encode(JSON.stringify(sorted)));
    return base64url(new Uint8Array(hash));
  }

  async sign(header, payload) {
    const encoder = new TextEncoder();
    const data = encoder.encode(
      `${base64url(encoder.encode(JSON.stringify(header)))}.${base64url(encoder.encode(JSON.stringify(payload)))}`
    );
    const signature = await crypto.subtle.sign(
      { name: 'ECDSA', hash: 'SHA-256' },
      this.privateKey,
      data
    );
    return `${base64url(encoder.encode(JSON.stringify(header)))}.${base64url(encoder.encode(JSON.stringify(payload)))}.${base64url(new Uint8Array(signature))}`;
  }
}

// DPoP validation middleware
async function validateDPoP(req, res, next) {
  const authHeader = req.headers.authorization;
  const dpopHeader = req.headers['dpop'];

  if (!authHeader || !dpopHeader) return res.status(401).json({ error: 'DPoP required' });

  const token = authHeader.slice(7);
  const dpopParts = dpopHeader.split('.');

  // Validate DPoP proof
  const dpopHeader_decoded = JSON.parse(atob(dpopParts[0]));
  const dpopPayload_decoded = JSON.parse(atob(dpopParts[1]));

  // Verify HTTP method and URL match
  if (dpopPayload_decoded.htm !== req.method) return res.status(401).json({ error: 'Method mismatch' });
  if (dpopPayload_decoded.htu !== `${req.protocol}://${req.get('host')}${req.originalUrl}`) {
    return res.status(401).json({ error: 'URL mismatch' });
  }

  // Verify token hash
  const tokenHash = await hashAccessToken(token);
  if (dpopPayload_decoded.ath !== tokenHash) {
    return res.status(401).json({ error: 'Token hash mismatch' });
  }

  // Verify signature against JWK in header
  // ... signature verification logic

  next();
}

Token binding prevents token theft by making tokens cryptographically bound to the intended client.

Built by the developers of DodaTech

Doda Browser, DodaZIP & Durga Antivirus Pro