What HMAC Adds Over a Plain Hash
A hash tells you data was not corrupted; an HMAC tells you it was not corrupted and was produced by someone holding the secret key. That is why webhook signatures (Stripe, GitHub) and API request signing use HMAC-SHA256 rather than a bare hash - naively hashing secret+message is vulnerable to length-extension attacks, which the HMAC construction was designed to close. The construction, the attack and the verification pitfalls (timing-safe comparison above all) are covered in HMAC explained.
Computation happens in your browser through the Web Crypto API, so keys never leave the page. The nested structure looks like this:
HMAC(K, m) = H((K' ⊕ opad) || H((K' ⊕ ipad) || m))
- K - secret key
- m - message
- H - cryptographic hash function (SHA-256, SHA-512)
- K' - key padded to block size
- opad - outer padding (0x5c repeated)
- ipad - inner padding (0x36 repeated)
- ⊕ - XOR operation
- || - concatenation