How to Encode and Decode Base64:
Quick Tutorial
Decode any Base64 string back to readable text — or encode your own — in under a minute. Covers the URL-safe variant, CLI commands, and the errors that trip everyone up.
This tutorial shows you how to decode a Base64 string back to readable text, and how to encode text into Base64 — both in under a minute in the browser. It also covers the command-line equivalents, the URL-safe variant that trips people up, and how to recognize when a string is actually Base64 in the first place.
Step 1: Recognize Base64 When You See It
Before decoding, confirm what you have. Base64 strings use exactly 64 characters — A–Z, a–z, 0–9, +, and / — plus = for padding at the end. Length is always a multiple of 4. Typical examples:
SGVsbG8sIFdvcmxkIQ==
eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9
dXNlcm5hbWU6cGFzc3dvcmQ=
Two tells: one or two = signs at the end, and the prefix eyJ — that's {" encoded, which means the payload is JSON (JWTs start this way). If the string contains - or _ instead of + and /, it's the URL-safe variant; more on that in the troubleshooting section.
Step 2: Decode It
Open the Base64 Converter, paste the string into the input, and switch to Decode mode. The conversion happens in your browser — nothing is sent to a server, so decoding strings that contain credentials or tokens is safe.
Input:
dXNlcm5hbWU6cGFzc3dvcmQ=
Output:
username:password
That particular example is the format of an HTTP Basic Authentication header — which demonstrates the single most important fact about Base64: it is encoding, not encryption. Anyone can reverse it. Never treat Base64 as a way to hide data.
Step 3: Encode Text to Base64
Switch to Encode mode and type or paste your text. Common reasons to encode:
- Building a Basic Auth header by hand: encode
user:pass, then sendAuthorization: Basic dXNlcjpwYXNz. - Embedding binary-ish content in JSON or XML, which can only carry text.
- Creating test fixtures for code that decodes Base64.
Note that Base64 makes data bigger, not smaller: every 3 bytes of input become 4 characters of output, a fixed 33% size increase. That's the price of representing arbitrary bytes using only safe printable characters.
Worked Example: Reading a Kubernetes Secret
Kubernetes stores secrets Base64-encoded. Running kubectl get secret db-creds -o yaml gives you:
data:
username: YWRtaW4=
password: czNjcjN0LXB3
Paste YWRtaW4= into the converter in decode mode → admin. This is the fastest way to inspect a secret when you don't remember the kubectl flags — and it makes the security point concrete: anyone who can read the YAML can read the secret. Base64 in Kubernetes exists to safely carry binary values in YAML, not to protect them.
Encoding and Decoding Without the Tool
Command line
# Encode (macOS and Linux)
echo -n "Hello, World!" | base64
# → SGVsbG8sIFdvcmxkIQ==
# Decode — note the flag differs by OS
echo "SGVsbG8sIFdvcmxkIQ==" | base64 -d # Linux
echo "SGVsbG8sIFdvcmxkIQ==" | base64 -D # macOS (capital D)
The -n on echo matters: without it, echo appends a newline and that newline gets encoded too, producing a different string (SGVsbG8sIFdvcmxkIQo= — note the different ending). This is the #1 cause of "my Base64 doesn't match" bugs in shell scripts.
In code
// JavaScript (browser)
btoa("Hello") // encode → "SGVsbG8="
atob("SGVsbG8=") // decode → "Hello"
// Node.js
Buffer.from("Hello").toString("base64")
Buffer.from("SGVsbG8=", "base64").toString()
# Python
import base64
base64.b64encode(b"Hello") # b'SGVsbG8='
base64.b64decode("SGVsbG8=") # b'Hello'
Common Problems and Fixes
Decode produces garbage characters
Either the input isn't Base64 (it might be hex, or a hash — hashes like SHA-256 aren't reversible at all; see the Hash Generator), or the decoded bytes aren't text. A Base64 string can encode an image, a ZIP, or any binary — decoding those to "text" yields mojibake. If you suspect an image, try the Base64 Image Viewer instead.
"Invalid character" error on a string with dashes or underscores
That's Base64url, the URL-safe variant used in JWTs and web APIs: + becomes - and / becomes _, and padding is often dropped. Replace - with + and _ with /, add = until the length is a multiple of 4, then decode. For JWTs specifically, the JWT Decoder handles all of this automatically.
btoa() throws "characters outside of the Latin1 range"
JavaScript's btoa() only handles single-byte characters, so any emoji or non-Latin text breaks it. Encode the UTF-8 bytes first: btoa(String.fromCharCode(...new TextEncoder().encode(str))), or use Buffer in Node. The online converter handles UTF-8 correctly out of the box.
Decoded JSON is still unreadable
Base64-decoded JSON usually comes out as one long line. Paste it into the JSON Formatter to indent it.
FAQ
Is Base64 encryption?
No. It's a reversible text representation of bytes with zero secrecy. Anyone with the string can decode it instantly. If you need actual secrecy, use real encryption like AES — see the AES Encrypt tool.
Why does Base64 end with = signs?
Padding. Base64 processes input in 3-byte groups producing 4 characters each. When the input length isn't divisible by 3, the last group is padded: 1 leftover byte → ==, 2 leftover bytes → =. Some systems (JWTs, some APIs) omit padding entirely, which most decoders tolerate.
Why do JWTs and data URIs use Base64?
Because both need to carry arbitrary bytes through channels that only accept text — URLs and HTTP headers for JWTs, HTML/CSS attributes for data URIs. JWTs use the URL-safe variant; data URIs (like data:image/png;base64,iVBOR…) use standard Base64. The web encoding guide compares Base64 against URL encoding and HTML entities in depth, and Base64 Explained walks through the encoding bit-by-bit with playable diagrams.
Does Base64 work for images and files?
Yes — that's one of its main jobs. Encode an image with the Image to Base64 tool to embed it directly in CSS or HTML. Keep it small: because of the 33% size overhead, inlining anything beyond a few KB usually hurts page performance more than an extra HTTP request would.