You open an API response, a config file or the source of an email, and somewhere in the middle sits a line like this:
SGVsbG8sIFdvcmxkIQ==
It looks like a cat walked across the keyboard. It isn’t random, though. Run it through a Base64 decoder and it reads “Hello, World!”
Base64 shows up in login tokens, email attachments, embedded images and API payloads. Most people only think about it when something breaks. This guide shows you how to decode Base64 step by step, whether you are working with text, images or JWT tokens, and how to fix the errors that eat up an afternoon.
Quick answer: how to decode Base64
A Base64 decoder turns Base64-encoded text back into its original data. That data might be plain text, an image, a PDF or the JSON inside a login token. Base64 is an encoding, not encryption, so decoding needs no password or key. Anyone can reverse it.
That last point has real privacy consequences, and we’ll get to them below.
What is Base64, and why does it exist?
Computers store everything as bytes. Many older systems, email being the classic example, were designed to carry plain text only. Push raw binary data such as an image or a ZIP file through them and it can get corrupted or rejected.
Base64 gets around this by rewriting any data using a safe alphabet of 64 characters:
- Uppercase letters A to Z
- Lowercase letters a to z
- Digits 0 to 9
- Two symbols:
+and/ - The
=sign, used as padding at the end
The format is defined in RFC 4648. The price you pay is size. Every 3 bytes of input become 4 characters of output, so Base64 data is about one third larger than the original. A 1,024-byte file turns into 1,368 characters.
How Base64 decoding works (a small worked example)
You will almost never decode by hand. Still, seeing it once makes the errors later much easier to understand.
Take the string TWE=. Decoding goes like this:
- Each character maps to a number from 0 to 63. T is 19, W is 22 and E is 4.
- Each number becomes 6 bits:
010011,010110,000100. - Join them into one stream:
010011010110000100. - Regroup into 8-bit bytes and discard the leftover bits:
01001101is “M” and01100001is “a”.
The result is “Ma”. The = told the decoder that the last group was short, so it knew to throw away the extra bits.
That is the whole reason padding exists, and it explains why a missing = is one of the most common decode failures:
| Original length | Example | Base64 output | Padding |
|---|---|---|---|
| Multiple of 3 bytes | Man | TWFu | None |
| Leaves 2 bytes over | Ma | TWE= | One = |
| Leaves 1 byte over | M | TQ== | Two == |
Where you’ll run into Base64
| Where it appears | What’s inside | Why Base64 is used |
|---|---|---|
| Email attachments (MIME) | Documents, images | Email was built to carry text |
| Data URIs in HTML and CSS | Small images, fonts | Avoids a separate file request |
| JWT tokens | JSON header and payload | Compact and URL-friendly |
| API requests and responses | Files, binary data | JSON strings cannot carry raw binary |
| PEM files | Certificates, keys | Binary data stored as plain text |
| HTTP Basic Auth headers | username:password | Header formatting, not security |
If you work with web apps or APIs, you will run into several of these sooner or later.
How to decode Base64 to text
For plain text, the job is simple: paste the string into a decoder and read the output. Two things trip people up.
Character encoding. Base64 decodes to bytes, and bytes only turn into readable text when they are interpreted with the right character set. UTF-8 is the most widely used one. If you see é where you expected é, the text was read with the wrong encoding.
The atob() trap in JavaScript. The browser’s built-in atob() returns a “binary string” with one character per byte. That is fine for plain ASCII, but emoji and non-English characters come out garbled. For UTF-8 text, convert the bytes with TextDecoder instead.
If you would rather decode in code, these are the usual one-liners:
| Environment | How to decode |
|---|---|
| Node.js | Buffer.from(str, 'base64').toString('utf8') |
| Browser JavaScript | atob(str) (ASCII only; use TextDecoder for UTF-8) |
| Python | base64.b64decode(str) |
| Linux (GNU coreutils) | echo 'str' | base64 --decode |
| PowerShell | [Text.Encoding]::UTF8.GetString([Convert]::FromBase64String("str")) |
One note for Python users: base64.urlsafe_b64decode() expects correct padding, and JWT segments have their padding stripped. If you get an “Incorrect padding” error, add = characters until the length is a multiple of 4.
How to convert Base64 to an image or file
Decoding to a file works the same way, except you save the bytes instead of reading them as text. Two details make it easier.
Data URIs label themselves. If your string starts with data:image/png;base64,, the part before the comma tells you the file type and the part after is the actual data. Remove the prefix before decoding.
Raw Base64 still hints at the file type. Most file formats begin with a recognizable signature, and that signature stays recognizable after encoding:
| Starts with | Usually means |
|---|---|
iVBORw0KGgo | PNG image |
/9j/ | JPEG image |
R0lGOD | GIF image |
JVBERi0 | PDF document |
If you have an unlabelled string and no idea what it is, check the first few characters. It is a quick way to pick the right file extension before you save anything.
A quick performance note: embedding Base64 images directly in HTML or CSS saves a network request, but it makes the data about a third bigger and stops the browser from caching the image on its own. It suits tiny icons. It is a poor fit for photos.
How to decode a JWT token
A JSON Web Token (JWT), specified in RFC 7519, looks like three Base64URL chunks separated by dots:
header.payload.signature
| Part | What it contains | Readable by decoding? |
|---|---|---|
| Header | Token type and signing algorithm (such as HS256 or RS256) | Yes |
| Payload | Claims: who the user is, when the token expires | Yes |
| Signature | Proof the token wasn’t altered | It decodes, but only means something when checked with the key |
The payload usually carries a few standard claims:
| Claim | Meaning |
|---|---|
iss | Issuer: who created the token |
sub | Subject: usually the user ID |
aud | Audience: who the token is meant for |
iat | Time the token was issued |
nbf | Token is not valid before this time |
exp | Time the token expires |
Time claims are Unix timestamps in seconds, not milliseconds. This causes a classic bug. JavaScript’s Date.now() returns milliseconds, so comparing it directly with exp gives wrong results. Going the other way, new Date(exp) without multiplying by 1,000 gives you a date in January 1970. Convert the units first and the confusion disappears.
Decoding is not verifying
Decoding a JWT shows you what the token claims. It does not prove those claims are true. Only someone holding the secret or public key can verify the signature. For debugging, decoding is exactly what you need. For deciding who gets access to what, verification on the server is the only thing that counts.
Also remember that a standard signed JWT is encoded, not encrypted. Anyone who holds it can read the payload, so never put passwords, card numbers or sensitive personal data inside. Encrypted tokens (JWE) do exist, but they have five parts and cannot be read by simple Base64 decoding.
Standard Base64 vs URL-safe Base64
The + and / characters cause trouble inside URLs, where they carry special meanings. So a variant called Base64URL swaps them out:
| Standard Base64 | URL-safe Base64 | |
|---|---|---|
| Character 62 | + | - |
| Character 63 | / | _ |
Padding = | Used | Optional; left out in JWTs |
| Commonly found in | Email, files, general data | JWTs, URL parameters |
If a decoder rejects your string with an “invalid character” message and you can see - or _ in it, you almost certainly have the URL-safe version.
Common Base64 decode errors and how to fix them
| What you see | Likely cause | Fix |
|---|---|---|
| “Invalid character” | URL-safe string fed to a standard decoder | Replace - with + and _ with /, or use a decoder with a URL-safe option |
| “Incorrect padding” | Trailing = was lost while copying | Copy the full string again, or add = until the length is a multiple of 4 |
| Garbled text | Wrong character encoding, or the data isn’t text | Try UTF-8; if it’s a file, decode it as a file |
| Output still looks like Base64 | The data was encoded twice | Decode the result once more |
| Unreadable symbols | The data was compressed or encrypted before encoding | The decode worked; the next step is decompression or decryption |
| Works on one line, fails on several | Line breaks inside the string | Remove whitespace, or decode line by line |
Go through that list from top to bottom and you will find the cause most of the time.
Is Base64 encryption? (No, and it matters)
This is the biggest misunderstanding around Base64. Encoding changes the format of data so systems can handle it. Encryption hides data from anyone without a key. Base64 only does the first job.
Treat anything in Base64 as plain text wearing a thin disguise. A few practical rules follow from that:
- Don’t store secrets in Base64 and call them protected. A Basic Auth header is just
username:passwordin Base64, readable by anyone who sees it. - Think about where you paste real tokens. Before using any online tool with sensitive data, read how it handles your input.
- Never run decoded content you didn’t write. Base64 is sometimes used to obfuscate malicious scripts. Decode to read, not to execute.
How to choose an online Base64 decoder
Almost any tool can turn SGVsbG8= into “Hello”. The differences show up when your input isn’t tidy. Here is a simple checklist:
| What to check | Why it matters |
|---|---|
| Text, file and JWT support | Real work involves more than plain text |
| URL-safe input | JWTs and URL parameters use this variant |
| Image preview | Confirms you decoded the right thing |
| Clear error messages | “Invalid input” tells you nothing; a specific hint saves time |
| Batch decoding | Useful when you have a list of values |
| Privacy statement | Tells you what happens to what you paste |
Features differ from tool to tool, so make sure the ones you need are actually there.
Need to decode something right now?
If you have a string in front of you and just want to see what’s inside, you can paste it into the Base64 decoder on BytePriva. And when you need to go the other way, there is a Base64 encoder too.
Frequently asked questions
What is a Base64 decoder?
A Base64 decoder converts a Base64-encoded string back into its original form, whether that is text, an image, a file or structured data such as a JWT payload.
Is Base64 encryption?
No. Base64 is a reversible encoding with no key or password. Anyone can decode it, so it provides no security on its own.
Why does Base64 end with == or =?
The equals signs are padding. Base64 works in groups of 3 bytes. When the input doesn’t divide evenly, one or two = characters complete the last group.
How do I decode Base64 to an image?
Remove the data:image/...;base64, prefix if there is one, decode the rest into bytes, and save the bytes with the matching extension such as .png or .jpg. A decoder that supports files will do this and show a preview.
Can I decode a JWT without the secret key?
Yes. The header and payload are only Base64URL-encoded, so you can read them without any key. You cannot verify the signature without the secret or public key.
What is the difference between Base64 and Base64URL?
Base64URL replaces + with - and / with _, and often omits the padding, so the result is safe to use inside URLs. JWTs use this variant.
Why is my decoded text full of strange characters?
Usually one of two things: the text was read with the wrong character encoding (try UTF-8), or the original data wasn’t text at all, for example an image, a compressed file or encrypted data.
Does Base64 make files bigger?
Yes, by roughly 33 percent, because every 3 bytes of data become 4 characters.
Is it safe to decode Base64 online?
It depends on the tool. Decoding is harmless in itself, but the concern is where your input goes. For tokens, keys or private files, use a decoder that processes data locally in your browser and states so clearly, and avoid pasting live production secrets anywhere you don’t trust.
Can Base64 hide malware?
It can. Base64 is often used to obfuscate scripts, which is why security teams decode suspicious strings during analysis. If you decode something you don’t recognise, read it and don’t execute it.
Key takeaways
- Base64 carries binary data through text-only channels. It does not protect that data.
- Most decode errors come from padding, URL-safe characters, character encoding or stray whitespace.
- Anyone holding a JWT can read its payload, and decoding says nothing about whether it is authentic.
- JWT time claims are in seconds, which catches out many developers.
- For sensitive data, check how a tool handles your input before pasting it.
Disclaimer
This article is for general educational purposes only. Decoding Base64 only reveals data; it does not confirm that the data is authentic or safe, so never run or trust decoded content from an unknown source. Test any code examples in a safe environment before using them in production, and avoid pasting real passwords, private keys or live secrets into online tools.