HMAC Output: Hex vs Base64 Encoding
Compare hexadecimal and Base64 encoding formats for HMAC output. Learn which format to use in HTTP headers, webhooks, JWTs, and database storage for optimal results.
Detailed Explanation
HMAC Output Encoding: Hex vs Base64
HMAC functions produce raw binary bytes as output. To use these bytes in text-based systems (HTTP headers, JSON payloads, database columns), they must be encoded. The two dominant encoding formats are hexadecimal and Base64.
Hexadecimal Encoding
Hex encoding represents each byte as two characters from 0-9 and a-f:
- HMAC-SHA256: 32 bytes → 64 hex characters
- HMAC-SHA512: 64 bytes → 128 hex characters
- Advantages: Case-insensitive comparison, no special characters, easy visual inspection, universally supported
- Disadvantages: 2x expansion ratio (each byte becomes 2 characters)
Example: a4331f76e88d9e76e5f1a7d88e4c7f2b9c3e5d6a7b8c9d0e1f2a3b4c5d6e7f8a
Base64 Encoding
Base64 uses a 64-character alphabet (A-Z, a-z, 0-9, +, /) with = padding:
- HMAC-SHA256: 32 bytes → 44 Base64 characters
- HMAC-SHA512: 64 bytes → 88 Base64 characters
- Advantages: ~33% more compact than hex, standard in HTTP and MIME contexts
- Disadvantages: Case-sensitive,
+and/require URL encoding, padding characters
Example: pDMfduiNnnbl8afYjkx/K5w+XWp7jJ0OHyojtMXW748=
Base64url Encoding
A URL-safe variant replaces + with - and / with _, and typically omits padding:
- Used in JWTs, OAuth, and URL query parameters
- Same compactness as standard Base64
- No need for percent-encoding in URLs
Which Format to Use
| Context | Recommended Format | Reason |
|---|---|---|
| Webhook signatures | Hex | Industry convention (Stripe, GitHub) |
| HTTP headers | Base64 or Hex | Both common; match the API spec |
| JWTs | Base64url | Required by RFC 7515 |
| Database storage | Binary/Hex | Efficient storage and indexing |
| Logging | Hex | Easier to read and compare visually |
| URL parameters | Base64url | No special characters to escape |
Comparison Pitfalls
When comparing HMAC values, always use constant-time comparison functions to prevent timing attacks. Never use simple string equality (===) in security-critical code. Use crypto.timingSafeEqual() in Node.js or hmac.compare_digest() in Python.
Use Case
Choosing the correct output encoding is essential when integrating HMAC signatures into webhook verification endpoints, building JWT libraries, designing API authentication headers, or storing computed MACs in databases.