🛡️ Compares two values in constant time, so the comparison leaks no information about where they differ.

Warning

Use this instead of === whenever one side is a secret — an HMAC digest, an API key, a session token or a password hash. A plain === returns as soon as it hits the first differing byte, and that timing difference lets an attacker recover the expected value one byte at a time.

Syntax

TypeScript
import { timingSafeEqual } from '@opentf/std';

timingSafeEqual(
  a: string | ArrayBuffer | ArrayBufferView,
  b: string | ArrayBuffer | ArrayBufferView,
): boolean;

Parameters

NameTypeDescription
astring | ArrayBuffer | ArrayBufferViewThe first value.
bstring | ArrayBuffer | ArrayBufferViewThe second value.

Returns

true when both values hold the same bytes, otherwise false.

Strings are compared by their UTF-8 bytes. The comparison always scans the longer of the two inputs, so the running time reveals nothing beyond the input lengths — which are not secret for digests of a fixed size.

Throws a TypeError if either value is not a string, ArrayBuffer or ArrayBufferView.

Examples

Verifying a webhook signature:

TypeScript
const expected = await hmacSHA256(signingSecret, rawBody);

if (!timingSafeEqual(expected, request.headers.get('x-signature'))) {
  throw new Error('Invalid signature');
}

Comparing raw bytes:

TypeScript
timingSafeEqual(new Uint8Array([1, 2, 3]), new Uint8Array([1, 2, 3])) //=> true
timingSafeEqual('abc', 'abd') //=> false
timingSafeEqual('abc', 'abcd') //=> false
Last updated on
Edit this page