HMAC-SHA256 is a keyed-hash message authentication code that combines the SHA-256 cryptographic hash with a shared secret key, producing a 32-byte tag that any party holding the same secret and exact message bytes can recompute. To generate an HMAC-SHA256 signature, choose SHA-256, supply the secret and the message as exact UTF-8 text or precise hexadecimal bytes, and read back the full tag in lowercase hex or padded Base64. The operation runs through the browser's Web Cryptography API, so inputs never leave the current tab. Byte identity is essential: an extra newline, a stray space, a different encoding of the same word, or a trimmed tag will produce a different signature and break verification on the server. The tag does not hide the message; it only proves that whoever produced it held the key and that the message bytes are unchanged in transit. For API webhooks, signed URLs, JWTs and similar protocols, you must always read the required hash, key format, message canonicalization and output encoding directly from the governing specification before you generate a signature.

how to generate hmac sha256 signature
how to generate hmac sha256 signature

What HMAC-SHA256 Does and Why APIs Use It

Servers use HMAC-SHA256 to authenticate an incoming request without sending the secret across the wire. The client combines a shared secret with the exact request bytes, computes the 32-byte tag, and ships it in a header. The server repeats the calculation with its copy of the secret and accepts the request only when both tags match. This proves that the request came from a holder of the key and that no byte was altered in transit. Common places you will see HMAC-SHA256 include webhook signing on platforms such as Stripe, GitHub, and Slack, JWT HMAC algorithms such as HS256, OAuth 1.0a request signing, and many internal REST API conventions. None of these protocols hide the message body; they only prove its integrity and origin.

Hash Variant and Tag Length

The HMAC Generator supports three underlying hashes, and the protocol you follow determines which one to pick. HMAC-SHA256 always returns 32 bytes regardless of message length, HMAC-SHA384 always returns 48 bytes, and HMAC-SHA512 always returns 64 bytes.

HashTag length (bytes)Tag length (hex chars)Tag length (Base64 chars)
SHA-256326444
SHA-384489664
SHA-5126412888

If a protocol says "HMAC-SHA256" but accepts a longer tag, something else is being prepended (often an algorithm identifier like "sha256=" or a timestamp envelope). Do not strip or pad the tag yourself unless the specification explicitly requires it.

Picking the Exact Bytes: UTF-8 vs Hex

The HMAC Generator lets you set UTF-8 or hex independently for the key and for the message, because real protocols hand you each field in a different format.

  • UTF-8 mode treats the input as Unicode text and encodes it with the UTF-8 byte sequence. The word "café" becomes five bytes (c, a, f, then a two-byte é), CJK characters occupy three bytes each, and emoji occupy four bytes each. Use UTF-8 mode when the protocol passes the secret and the message as strings.
  • Hex mode requires an even number of hexadecimal digits and rejects 0x prefixes, spaces, colons and odd nibbles. A leading zero is preserved: 0a is one byte, not the same as a. Use hex mode for published test vectors, raw binary fields, and anything the specification shows you as bytes. Each decoded field is capped at 1,000,000 bytes, so payloads above that limit will be rejected before the tag is calculated.

If only one field is documented in hex and the other is documented as a string, switch the modes separately for each box. Pasting a hex string into UTF-8 mode will hash the literal ASCII characters of that string ("6b 65 79" instead of the three bytes "key"), which is almost never what the protocol expects.

Generate an HMAC-SHA256 Signature

  1. Open the HMAC Generator and confirm the algorithm selector shows SHA-256. Change it only if your protocol explicitly calls for SHA-384 or SHA-512.
  2. Set the key encoding. Pick UTF-8 if the specification hands you the secret as a string; pick hex if it quotes the secret as bytes (for example, the 0b0b0b0b... keys in RFC 4231). Paste the key with no extra whitespace, no surrounding quotes, and no 0x prefix.
  3. Set the message encoding the same way. Use UTF-8 for human-readable request bodies, canonical strings, JSON payloads, and query strings; use hex for binary blobs and published test vectors. Preserve exactly the bytes the specification defines, including any trailing newline or deliberate absence of newline.
  4. Generate the tag. The HMAC Generator returns the full 32-byte SHA-256 result rendered both as lowercase hex and as padded standard Base64, from the same single calculation.
  5. Copy the encoding your protocol demands. Most webhooks expect hex, others expect standard Base64, and a few expect Base64url. If the spec asks for Base64url, convert the displayed Base64 yourself by swapping + for -, swapping / for _, and stripping the trailing = padding; the tag bytes are identical, only the character set changes.
  6. Verify against a known test vector from the specification before sending the tag in production. The HMAC Generator is locked to eight full RFC 4231 conformance tags, so a mismatch on a published vector points at your input bytes, not the calculation.

Why HMAC-SHA256 Signatures Mismatch Across Tools

When the same secret and the same message produce different tags in two systems, the gap is almost always one of these:

  • Wrong hash. SHA-256, SHA-384, and SHA-512 produce completely different tags on the same input. Confirm the algorithm selector and the library configuration agree.
  • Wrong encoding. UTF-8 text "ñ" is two bytes (0xC3 0xB1), but Latin-1 "ñ" is one byte (0xF1). Hash both and you get different tags. BOM characters at the start of a string are a common silent culprit.
  • Stray whitespace. An extra newline, a trailing space, or a tab inside a JSON payload silently changes the digest. Canonicalize the message exactly as the specification demands.
  • Tag truncation. Some legacy systems used only the leftmost 16 bytes of an HMAC-SHA256 tag. Modern protocols require the full 32 bytes; do not trim unless the specification says so.
  • Base64url vs standard Base64. The tag bytes are identical but the character set differs (+ versus -, / versus _, padding rules). Decoding either must yield the same 32 bytes.
  • Algorithm prefix. Headers like sha256=abcdef... prepend a literal label that is part of the compared string, not part of the tag itself. Strip or include the prefix exactly as the spec dictates.

Run through this list before assuming the secret is wrong. On the server, compare tags with a constant-time function so timing leaks do not help an attacker guess bytes, as recommended by NIST FIPS 198-1.

Key Handling for HMAC-SHA256

A weak or poorly managed key breaks the construction no matter how carefully you compute the tag. Use high-entropy random material generated for the protocol (a 256-bit or longer secret is typical), distribute it through a protected channel such as a secrets manager or out-of-band onboarding, separate keys by purpose so a leaked webhook key cannot forge API requests, and rotate after any suspected compromise. A human password is not automatically a strong HMAC key: if the application must accept a password, derive the actual key with the exact password-based KDF and parameters the protocol specifies, not by hashing the password on the client side. Avoid pasting production secrets into shared or untrusted devices; the HMAC Generator runs entirely in the browser and does not send inputs anywhere, but a borrowed laptop is still a borrowed laptop. Successful agreement on a tag proves only that two parties hold the same secret and agree on the exact bytes of the message; it does not prove confidentiality, and it does not protect against a leaked key.