Base64 decoding takes ASCII characters from the 64-character alphabet (A-Z, a-z, 0-9, +, /, plus = for padding) and reverses the encoding to recover the original bytes. The tool above runs entirely in your browser; no input ever leaves your machine. The decoder accepts both standard base64 and the URL-safe base64url variant (which uses - and _ instead of + and /), and handles missing-padding inputs that many real-world base64 strings leave off.
How the decoding works
Decoding takes the input 4 ASCII characters at a time and produces 3 bytes (the inverse of base64 encoding). For each 4-character group:
- Each character maps back to its 6-bit index in the 64-character alphabet.
- The 4 × 6-bit groups are concatenated into 24 bits.
- Those 24 bits are reread as 3 × 8-bit bytes.
Worked example. Decoding "Q2F0":
Chars: Q 2 F 0
Index: 16 54 5 52
Binary (6-bit):
010000 110110 000101 110100
Concatenated (24 bits):
010000110110000101110100
Reread as 8-bit bytes:
01000011 01100001 01110100
Hex: 0x43 0x61 0x74
ASCII: C a t
Output: "Cat"
When the input length isn’t a multiple of 4, the encoder typically padded with = characters. The decoder strips those before processing. A 4-character group ending in one = produces 2 output bytes; ending in two == produces 1 output byte; ending in zero produces 3 output bytes.
Standard base64 vs base64url
The two variants differ in two characters:
| Position 62 | Position 63 | Variant | Used in |
|---|---|---|---|
+ | / | Standard base64 (RFC 4648 §4) | MIME, general data encoding |
- | _ | Base64url (RFC 4648 §5) | URLs, JSON Web Tokens, HTTP headers |
A base64url string with no padding is what you’ll see in a JWT (the .-separated parts of a JWT are base64url-encoded with = padding stripped). The decoder needs to handle both variants and add back missing padding before processing — a base64url string of length not divisible by 4 needs = characters appended until it is.
Common decode errors
Three error classes show up in real-world base64 input:
- Whitespace and newlines. Many tools emit base64 with line breaks every 76 characters (per MIME conventions). The decoder must strip whitespace before processing or it fails with an “invalid character” error.
- Mixed alphabets. A string that mixes
+/with-_is not valid base64 of either flavor. This is usually a bug upstream — typically a tool that re-encoded a base64url payload as standard base64 without normalizing. - Truncated input. A decoded string ending mid-group (length mod 4 = 1 after stripping padding) is not recoverable; the encoder produced output it shouldn’t have. Length mod 4 = 2 or 3 with stripped padding can be recovered by adding the missing
=characters.
The decoder above accepts both variants, normalizes whitespace, and handles missing padding. For pure standard base64 with strict validation, use a strict decoder library; for round-tripping arbitrary real-world input, the lenient approach is more useful.
What base64 isn’t
Base64 is encoding, not encryption. Anyone with the encoded string and 30 seconds can recover the original bytes — that’s the point. If you find a value that’s “encrypted” only by being base64-encoded, it isn’t encrypted at all. For credential or payload protection, use authenticated encryption (AES-GCM, ChaCha20-Poly1305) with a real key, then base64-encode the ciphertext if you need ASCII-safe transport.
Base64 is also not compression. Decoding produces bytes 1:1 with the original; encoding inflates by ~33% (4 ASCII bytes per 3 input bytes). If size matters, compress first (gzip, zstd) and then encode.
For the inverse direction, see base64 encoding: what it is, when to use it, and what it isn’t. For the most common real-world consumer of base64url, see JWT decoding — JWTs are three base64url-encoded segments separated by dots.