DEV Community

Cover image for How to decode a Base64 string (4 reliable ways)
Skojio Community
Skojio Community

Posted on • Originally published at skojio.com

How to decode a Base64 string (4 reliable ways)

You copied a blob of letters and numbers out of a config file, a JWT, or an API response, and you need to know what it actually says. It looks like gibberish — SGVsbG8sIHdvcmxkIQ== — but the trailing == gives it away: that's Base64, and it decodes back to plain text in seconds.

There are four reliable ways to decode it, depending on where you are and how awkward the string is. If you'd rather skip the command-line flags entirely, the Skojio Base64 decoder turns any string back into text or a downloadable file in one paste. Here's each method, and what to do when a string refuses to decode.

What a Base64 string actually is (and why it's not encryption)

Base64 is a binary-to-text encoding. It maps arbitrary bytes onto 64 printable ASCII characters — A–Z, a–z, 0–9, +, and / — so that binary data survives transport through systems that only accept text, like email headers, JSON fields, and URLs.

Every 3 bytes of input become 4 characters of output, which is why Base64 is always about 33% larger than the source. The = signs at the end are padding: they pad the final group up to a multiple of four characters when the input length doesn't divide evenly by three.

src="/blog/figures/base64-byte-mapping.jpg"
alt="The text 'Man' shown as three bytes, regrouped into four 6-bit chunks, and mapped to the Base64 characters T, W, F and u"
caption="Three bytes of text (24 bits) regroup into four 6-bit chunks — one Base64 character each."
/>

The critical point: Base64 has no key. It is trivially reversible by anyone, so it provides zero secrecy. A Base64-encoded password is a plaintext password with extra steps. Decoding it isn't decryption — it's just reading.


Because a Base64 string is plaintext, pasting one into a random online decoder hands your data to that server. If the blob is a JWT, an API response, or anything you'd treat as a credential, decode it locally — in the terminal, the browser console, or a client-side tool that never sends it over the network.

You'll meet Base64 most often in four places: data URIs (data:image/png;base64,… that inline an image straight into CSS or HTML), JWTs (whose header and payload are Base64url-encoded JSON), HTTP Basic Auth (the Authorization: Basic header is just base64(user:password)), and email attachments (MIME wraps binary parts in Base64). Recognising which one you're holding tells you what the decoded output should look like before you even run the command.

Decode a Base64 string in the terminal with base64 --decode

The fastest method on macOS and Linux is the built-in base64 command:

echo "SGVsbG8sIHdvcmxkIQ==" | base64 --decode
# → Hello, world!
Enter fullscreen mode Exit fullscreen mode

src="/blog/figures/base64-terminal.jpg"
alt="A terminal showing 'echo SGVsbG8sIHdvcmxkIQ== | base64 --decode' returning 'Hello, world!', and the reverse encode command"
caption="Decoding and re-encoding 'Hello, world!' with the built-in base64 command."
/>

On older macOS the flag is capitalised:

echo "SGVsbG8sIHdvcmxkIQ==" | base64 -D
Enter fullscreen mode Exit fullscreen mode

If the decoded output is binary (an image, a gzip blob), don't print it to the terminal — redirect it to a file instead:

echo "$B64" | base64 --decode > output.png
Enter fullscreen mode Exit fullscreen mode

One terminal caveat: some PEM certificates and email payloads wrap Base64 at 64 characters per line. GNU base64 tolerates those newlines, but the BSD build on macOS can complain — pass -i to ignore non-alphabet characters, or strip the newlines with tr -d '\n' before piping.

On Windows, certutil or PowerShell do the same job:

[Text.Encoding]::UTF8.GetString([Convert]::FromBase64String("SGVsbG8="))
Enter fullscreen mode Exit fullscreen mode

Decode Base64 in the browser console with atob

Already in DevTools? The browser ships a decoder: atob (ASCII-to-binary).

atob("SGVsbG8sIHdvcmxkIQ==");
// → "Hello, world!"
Enter fullscreen mode Exit fullscreen mode

There's one sharp edge. atob returns a binary string, so any non-ASCII content — accented characters, emoji, anything UTF-8 — comes out mangled. The correct incantation for Unicode is:

new TextDecoder().decode(
  Uint8Array.from(atob(b64), (c) => c.charCodeAt(0))
);
Enter fullscreen mode Exit fullscreen mode

If you find yourself reaching for that snippet more than once, paste the string into the Base64 tool instead — it handles UTF-8 correctly by default, so café and 🚀 round-trip without the TextDecoder dance.

Why your Base64 string won't decode — padding, URL-safe, and UTF-8

Most "invalid Base64" errors come down to three causes:

  1. Missing padding. A valid Base64 string's length is a multiple of 4. If yours isn't, strict decoders reject it. Append = until the length divides by four — one or two signs is all it ever needs.
  2. URL-safe variant. Base64url, used in JWTs and URL query strings, swaps + for - and / for _, and usually drops padding entirely. A standard decoder chokes on it. Convert - back to + and _ back to / first, then re-pad.
  3. Stray whitespace. Strings copied from emails, certificates, or wrapped JSON often carry newlines or spaces. Strip them before decoding — most command-line tools fail on embedded whitespace even though the data is fine.

A JWT is the classic trap: it's three Base64url segments joined by dots. Split on the ., decode the first two segments, and you get the header and payload as JSON. The signature won't decode to anything readable — that's expected.

Data URIs hide a fourth gotcha. A string like data:image/png;base64,iVBORw0KGgo… isn't pure Base64 — the part you decode starts after the comma. Feed the whole data: prefix into a decoder and it fails; strip everything up to and including the comma first, then decode the remainder to recover the original file bytes.

If you only need to verify that a string is valid Base64 without caring about the output, check two things: the alphabet (only A–Z, a–z, 0–9, +, /, and trailing = for standard Base64) and the length-multiple-of-4 rule. Anything outside that alphabet means it's either URL-safe, corrupted, or not Base64 at all.

Decode any Base64 string in one paste

When the variant is ambiguous, the padding is missing, or the result is a file rather than text, stop fiddling with flags and paste it into a decoder that just works.

The Skojio Base64 encoder and decoder auto-detects standard and URL-safe input, fixes padding for you, decodes UTF-8 correctly, and lets you decode straight to a downloadable file for binary payloads. It runs entirely in your browser, so a JWT or an internal API token never leaves your machine — no upload, no account, no rate limit.

Recap

Where you are How to decode
macOS / Linux terminal base64 --decode (or -D)
Windows certutil -decode or FromBase64String
Browser DevTools atob() — wrap in TextDecoder for UTF-8
Awkward string, URL-safe, or a file Skojio Base64 decoder

Base64 is an encoding, not a secret. Once you can read it on demand, the blob in your config file stops being mysterious — and when the next one resists base64 --decode, paste it into the decoder and let it sort the padding out for you.

Top comments (0)