API cookbook
Verify HMAC signatures across languages
The same verification pattern in TypeScript, Python, Go, and Ruby. Constant-time compare; 5-minute timestamp window.
beginnerTypeScript · Python · Go · Ruby
TypeScript
import crypto from "node:crypto";
function verify(body: string, sig: string, ts: number, secret: string): boolean {
if (Math.abs(Date.now() / 1000 - ts) > 300) return false;
const expected = crypto.createHmac("sha256", secret)
.update(`${ts}.${body}`).digest("hex");
return crypto.timingSafeEqual(Buffer.from(expected), Buffer.from(sig));
}Python
import hmac, hashlib, time
def verify(body: str, sig: str, ts: int, secret: bytes) -> bool:
if abs(time.time() - ts) > 300:
return False
expected = hmac.new(secret, f"{ts}.{body}".encode(), hashlib.sha256).hexdigest()
return hmac.compare_digest(expected, sig)Go
import (
"crypto/hmac"
"crypto/sha256"
"encoding/hex"
"time"
)
func Verify(body, sig string, ts int64, secret []byte) bool {
if d := time.Now().Unix() - ts; d > 300 || d < -300 {
return false
}
mac := hmac.New(sha256.New, secret)
mac.Write([]byte(fmt.Sprintf("%d.%s", ts, body)))
expected := hex.EncodeToString(mac.Sum(nil))
return hmac.Equal([]byte(expected), []byte(sig))
}Ruby
require "openssl"
def verify(body, sig, ts, secret)
return false if (Time.now.to_i - ts).abs > 300
expected = OpenSSL::HMAC.hexdigest("SHA256", secret, "#{ts}.#{body}")
Rack::Utils.secure_compare(expected, sig)
end