Hex to Base64 Converter
Convert between hexadecimal and Base64 (or Base64url) directly — useful for crypto signatures, JWT debugging, and binary-to-text format hopping. Bidirectional, byte-accurate, browser-only.
Hex and Base64 Both Encode Bytes — Just Differently
Hexadecimal and Base64 are two ways to write the same thing: a sequence of bytes as printable ASCII. They differ in density and character set, not in what they represent. Hex uses 16 characters (0–9, a–f), one nibble (4 bits) per character, so two characters per byte. Base64 uses 64 characters (A–Z, a–z, 0–9, +, /) and packs 6 bits per character, so 4 characters per 3 bytes. Base64 is denser — about 67% the length of hex — but harder to read at a glance.
When You'll Need to Convert
Cryptography is the main place these encodings collide:
- HMAC signatures — OpenSSL prints them as hex, GitHub webhook headers use hex (
X-Hub-Signature-256: sha256=<hex>), Stripe uses Base64url (v1=<b64u>), Slack uses hex. - Hash digests — SHA-1, SHA-256, SHA-512 are typically displayed as hex, but JWT thumbprints and many key fingerprints use Base64url.
- JWT debugging — header and payload are Base64url-encoded JSON; signatures are Base64url-encoded bytes. Comparing a JWT signature to a hash digest requires hex ↔ Base64url conversion.
- Key material — you generate a key with
openssl rand -hex 32and need to paste it into a config that expects Base64. - Webhook secret rotation — copying a secret between providers that use different format conventions.
Base64 vs Base64url
Standard Base64 (RFC 4648 §4) uses these 64 characters: A-Z a-z 0-9 + / with = padding. The +, /, and = are problematic in URLs (they need percent-encoding), in filenames (slash is a path separator), and in HTTP headers. Base64url (RFC 4648 §5) solves this by substituting - for + and _ for /, and by convention dropping the = padding. The encoded bytes are identical; you can switch between the two with three character substitutions.
Format Cleanup the Tool Does for You
Real-world hex strings come in many flavors. The parser tolerates:
- Prefixes —
0x,0X,whsec_,sha256=are stripped automatically. - Whitespace, colons, dashes — formats like
ab:cd:eforAB CD EFwork without extra cleanup. - Mixed case — both
DEADBEEFanddeadbeefparse identically.
Base64 input similarly tolerates whitespace and missing padding. The parser auto-detects whether you've pasted standard Base64 (+/) or Base64url (-_) and decodes either correctly.
Doing It in Code
// Node.js
Buffer.from(hex, 'hex').toString('base64')
Buffer.from(hex, 'hex').toString('base64url') // Node 16+
Buffer.from(b64, 'base64').toString('hex')
// Python
import base64
base64.b64encode(bytes.fromhex(hex)).decode()
base64.urlsafe_b64encode(bytes.fromhex(hex)).rstrip(b'=').decode()
bytes.fromhex(hex) // hex string → bytes
bytes.fromhex(hex).hex() // bytes → lowercase hex string
// Browser (no Buffer)
function hexToBytes(h) {
const a = new Uint8Array(h.length / 2);
for (let i = 0; i < a.length; i++) a[i] = parseInt(h.substr(i*2, 2), 16);
return a;
}
function bytesToB64(a) {
return btoa(String.fromCharCode(...a));
} For working with HMAC signatures specifically, see the Webhook Secret Generator. To compute a hash from input, the Hash Generator outputs in both hex and Base64.
How to Use
- Pick a direction — Hex → Base64 / Base64url, or Base64 / Base64url → Hex.
- Paste your input — prefixes (0x, whsec_), whitespace, and colons are stripped automatically.
- Toggle 'Uppercase' if you need uppercase hex output (default is lowercase).
- Copy the result — output is byte-accurate; round-tripping (hex → b64 → hex) preserves the original.
Frequently Asked Questions
When do I need hex ↔ Base64 conversion?
Most often when debugging cryptography. Crypto APIs and tools mix encodings inconsistently: OpenSSL outputs hex; JWT uses Base64url; HMAC libraries vary by language. You'll convert when comparing a signature you computed to a signature in a webhook header, when debugging Stripe (Base64url) vs GitHub (hex) webhook signatures, or when copying a key between tools that disagree on format. The bytes are the same — only the text representation differs.
What's the difference between Base64 and Base64url?
Standard Base64 (RFC 4648 §4) uses A–Z, a–z, 0–9, +, / with = padding. Base64url (RFC 4648 §5) replaces + and / with - and _ to make output safe in URLs and filenames, and typically drops the = padding. JWT, JWS, and most modern web APIs use Base64url. The encoded bytes are identical; only three characters differ.
Can I include a 0x or whsec_ prefix in the input?
Yes — the parser strips common prefixes before decoding: '0x', '0X', 'whsec_', and 'sha256=' (used in webhook signatures). Whitespace, colons, and dashes inside hex strings are also ignored, so you can paste hex with formatting (e.g., 'ab:cd:ef' or 'AB CD EF') and it will work.
Does the case of hex characters matter?
No. Both lowercase (a-f) and uppercase (A-F) hex are accepted in input. Output is lowercase by default — toggle the option to get uppercase. Note that hex must have an even number of characters: each byte takes 2 hex digits, so an odd-length input is invalid.
How do I do this in code?
In Node.js: Buffer.from(hex,'hex').toString('base64') or Buffer.from(b64,'base64').toString('hex'). For Base64url, use 'base64url' (Node 16+) or post-process with .replace(/\+/g,'-').replace(/\//g,'_').replace(/=+$/,''). In Python: bytes.fromhex(hex).hex() ↔ base64.b64encode(bytes.fromhex(hex)).decode(). In the browser: this tool's source uses Uint8Array and btoa/atob — see the GitHub repo for the snippet.
Why does my converted output look longer?
Hex is 2 characters per byte (8 bits). Base64 is 4 characters per 3 bytes (≈1.33 chars/byte). So Base64 is shorter than hex — about 67% the length. If your Base64 output looks longer, you likely have whitespace or newlines in your hex input being preserved; the tool strips those automatically before re-encoding.
Comments
No comments yet. Be the first!