How to Generate and Verify HMAC Signatures in Python, Node.js, and Go

Learn how to generate and verify HMAC signatures in Python, Node.js, and Go. Secure your API with practical examples, code snippets, and a free online HMAC generator.

 min. read
October 7, 2025
Star us on GitHub and stay updated

APIs and webhooks depend heavily on HMAC (Hash-based Message Authentication Code) to ensure that every request you receive is authentic and unaltered.
Without signature verification, your application could be vulnerable to spoofing, data tampering, or replay attacks.

In this guide, you’ll learn:

  • What an HMAC signature is and how it works
  • How to generate and verify HMAC signatures in Python, Node.js, and Go
  • Common mistakes developers make and how to fix them
  • How to test your HMACs using a free online tool: Authgear’s HMAC Signature Generator & Verifier

What Is an HMAC Signature?

An HMAC (Hash-based Message Authentication Code) is a message authentication code created by combining a cryptographic hash function (like SHA256) with a secret key.
It ensures two critical properties:

  1. Integrity: The message hasn’t been modified in transit.
  2. Authenticity: The message came from a trusted source that knows the secret key.

The formula is conceptually simple:

HMAC = hash(secret_key + message)

Both the sender and receiver use the same secret key. If both sides compute the same HMAC value, the message is valid.

Why Use HMAC for APIs?

When APIs accept requests — for example, POST /payment — you need to verify that the request came from a trusted client.
HMAC-based signing ensures that only senders with the correct secret can generate a valid signature.

Typical flow:

  1. The client computes an HMAC for the request body.
  2. It sends the request with a header such as X-Signature: <hmac_value>.
  3. The server recalculates the HMAC and compares the two.
  4. If they match, the request is trusted and processed.

Many large platforms like Stripe, Shopify, GitHub, AWS, and Slack use HMAC for webhook verification and secure request signing.

How HMAC Works Step by Step

  1. Combine the secret and message.
  2. Hash the combination using a cryptographic algorithm (e.g., SHA256).
  3. Compare both signatures to confirm authenticity.
  4. Choose the right algorithm:
    • HMAC-SHA256 (recommended for most cases)
    • HMAC-SHA1 (legacy)
    • HMAC-SHA512 (for high-security applications)

Generate and Verify HMAC in Python

Python’s hmac and hashlib libraries make generating HMACs straightforward.

import hmac
import hashlib

message = b"Hello from Authgear"
secret = b"mysecretkey"

signature = hmac.new(secret, message, hashlib.sha256).hexdigest()
print("Generated HMAC:", signature)

expected_signature = "your_received_signature_here"
is_valid = hmac.compare_digest(signature, expected_signature)
print("Signature valid?", is_valid)

Always use compare_digest() for verification — it prevents timing attacks.You can try generating your own message and signature using Authgear’s free HMAC Signature Generator & Verifier tool.

Generate and Verify HMAC in Node.js

Node’s built-in crypto library provides similar functionality.

const crypto = require('crypto');

const message = 'Hello from Authgear';
const secret = 'mysecretkey';

// Generate HMAC
const signature = crypto
  .createHmac('sha256', secret)
  .update(message)
  .digest('hex');

console.log('Generated HMAC:', signature);

// Verify HMAC securely
const received = 'your_received_signature_here';
const isValid = crypto.timingSafeEqual(
  Buffer.from(signature),
  Buffer.from(received)
);
console.log('Signature valid?', isValid);

The timingSafeEqual function avoids timing-based comparison leaks.

Generate and Verify HMAC in Go

Go’s crypto/hmac package provides a clean interface for HMAC generation and verification.

package main

import (
  "crypto/hmac"
  "crypto/sha256"
  "encoding/hex"
  "fmt"
)

func main() {
  message := []byte("Hello from Authgear")
  secret := []byte("mysecretkey")

  mac := hmac.New(sha256.New, secret)
  mac.Write(message)
  expectedMAC := mac.Sum(nil)

  fmt.Printf("Generated HMAC: %s\n", hex.EncodeToString(expectedMAC))

  // Verification example
  receivedMAC, _ := hex.DecodeString("your_received_signature_here")
  valid := hmac.Equal(expectedMAC, receivedMAC)
  fmt.Println("Signature valid?", valid)
}

Real-World Example: Signing API Requests

Here’s an example of how HMAC signatures are used to authenticate API requests.

Client (Sender):

import requests, hmac, hashlib

url = "https://api.yourserver.com/webhook"
data = '{"order_id": "12345"}'
secret = b"mysecretkey"

signature = hmac.new(secret, data.encode('utf-8'), hashlib.sha256).hexdigest()
headers = {"X-Signature": signature}

requests.post(url, headers=headers, data=data)

Server (Receiver):

import hmac, hashlib
from flask import Flask, request

app = Flask(__name__)
SECRET = b"mysecretkey"

@app.route("/webhook", methods=["POST"])
def webhook():
    payload = request.data
    received_sig = request.headers.get("X-Signature")

    computed_sig = hmac.new(SECRET, payload, hashlib.sha256).hexdigest()
    if hmac.compare_digest(received_sig, computed_sig):
        return "Verified!", 200
    else:
        return "Invalid signature", 403

This ensures only authorized senders can submit valid requests.

Common Mistakes and How to Fix Them

Problem Likely Cause Solution
Invalid HMAC Signature Encoding mismatch (UTF-8 vs ASCII) Ensure both client and server use UTF-8 encoding consistently.
Mismatched Signatures Different algorithms used on each side Verify both are using the same algorithm, such as HMAC-SHA256.
Timing Attack Risk Using == for string comparison Always use secure comparison functions like compare_digest() or timingSafeEqual().
Unexpected Output Inconsistent digest formats (hex vs base64) Standardize output format with .hexdigest() or .base64encode() consistently.

Choosing the Right Hash Algorithm

Algorithm Security Level Performance Recommended Use
SHA-1 Weak / Legacy Very fast Only for backward compatibility with legacy systems.
SHA-256 Strong Balanced Recommended default for API signing and webhook verification.
SHA-512 Very strong Slightly slower Ideal for high-security or large-payload applications.

Testing Your HMAC Online

You can instantly generate and verify your HMAC signatures using Authgear’s free online tool: HMAC Signature Generator & Verifier

The tool supports:

  • Algorithms: SHA-1, SHA-256, SHA-512
  • Generate and Verify modes
  • Copy-to-clipboard output
  • Real-time hex output

It’s ideal for quickly testing your request signatures or debugging mismatched API keys.

Frequently Asked Questions

What algorithm does HMAC use?

HMAC can use SHA256, SHA1, or SHA512. SHA256 is most commonly used for APIs because it’s secure and widely supported.

Can I use HMAC for API authentication?

Yes. Platforms like Stripe, AWS, and GitHub use HMAC to sign API requests and webhooks.

What’s the difference between HMAC and hashing?

Hashing only ensures data integrity, while HMAC ensures both integrity and authenticity by including a shared secret key.

Is HMAC the same as JWT?

No. JWTs (JSON Web Tokens) can use HMAC algorithms (like HS256), but JWTs also carry payload data for stateless authentication.

What tools can I use to test HMAC online?

Authgear offers a free HMAC Signature Generator & Verifier, plus related tools like a JWK Generator, JWT Decoder, and the complete Authgear Developer Toolkit.

Preferences

Privacy is important to us, so you have the option of disabling certain types of storage that may not be necessary for the basic functioning of the website. Blocking categories may impact your experience on the website.

Accept all cookies

These items are required to enable basic website functionality.

Always active

These items are used to deliver advertising that is more relevant to you and your interests.

These items allow the website to remember choices you make (such as your user name, language, or the region you are in) and provide enhanced, more personal features.

These items help the website operator understand how its website performs, how visitors interact with the site, and whether there may be technical issues.

Thank you! Your submission has been received!
Oops! Something went wrong while submitting the form.