The mistake, and why it is so easy to make
I have reviewed code that stored an API key "encrypted" with Base64. I have seen a config file where the database password was Base64 and the comment above it said obfuscated. Neither developer was careless. Both had looked at the string, failed to read it, and concluded it was protected.
That is the whole trap. Base64 turns readable text into unreadable text, and unreadable feels like safe. But the transformation carries no key and no secret. Anyone who recognises the shape can reverse it in one command, in any language, or by pasting it into any of a thousand websites.
The four operations that get muddled are encoding, encryption, hashing and signing. They produce similar looking blobs and answer completely different questions. Once you can name which question you are asking, choosing between them stops being a judgement call.
Encoding: making data survive the journey
Encoding exists because some channels cannot carry arbitrary bytes. Email was built for text. URLs cannot contain spaces. A JSON string cannot hold a raw newline. Encoding rewrites data into a smaller alphabet that the channel will not mangle, and the rewrite is public and reversible by design.
Base64 maps every three bytes onto four characters from a 64 character alphabet, which is why encoded data is about 33% larger than what went in. That expansion is the price of safe transport and it is the reason inlining a large image as a data URI bloats a page more than people expect. RFC 4648 also defines a URL-safe variant that swaps the two characters which would otherwise need escaping in a query string, which is worth knowing before you debug why a token breaks in a URL but works everywhere else.
Percent encoding solves the same problem for URLs, and it is a separate thing with separate rules. A space becomes %20, and the encoding differs depending on whether you are writing a path segment, a query value or a form body. Encoding a whole URL when you meant to encode one parameter is a bug that produces a URL that looks right and resolves to nothing.
The Base64 encoder and decoder and the URL encoder and decoder both run in the browser, which matters here more than usual: pasting a token into a website to decode it means handing that token to whoever runs the website.
Encryption: making data unreadable without a key
Encryption is the one people think Base64 is. It transforms data using a key, and without that key the output is meaningless. Reversing it is possible only for whoever holds the key, which is what makes it protection rather than packaging.
The distinction to hold onto is that encoding has no secret and encryption is nothing but the secret. If you can reverse it with knowledge that is publicly documented, it is encoding. If reversing it requires something only you have, it is encryption. Base64 is fully documented in a public RFC, which settles the question.
A practical consequence: encrypted data usually gets Base64 encoded afterwards, because ciphertext is arbitrary bytes and most places you want to store it expect text. So the two do appear together constantly, and that co-occurrence is probably where the confusion breeds. The Base64 layer is the envelope. The encryption is the lock.
Hashing: a one way fingerprint
A hash takes input of any size and produces a fixed length fingerprint, and it does not go backwards. There is no key, and no amount of cleverness recovers the original from the digest, because information was genuinely discarded.
That one way property is what makes hashing right for passwords and wrong for anything you need to read again. A server storing password hashes can check whether you typed the right password without ever being able to tell you what it was. If a service can email you your existing password, it is not hashing them, and that tells you something about the rest of the system.
Two cautions worth carrying. First, not every hash suits every job: SHA-256 is excellent for verifying that a file downloaded intact and unsuitable on its own for storing passwords, where you want a deliberately slow algorithm such as bcrypt or Argon2 so that guessing costs the attacker real time. Second, MD5 and SHA-1 are broken for security purposes and survive only as checksums against accidental corruption. The hash generator here is for verification work of that kind, not for building an authentication system.
Signing: proving who sent it, not hiding it
Signing answers a different question again: not "can anyone read this" but "can anyone tamper with this without me noticing". A signature is computed over the data with a key, and it proves the data came from the key holder and has not changed since.
The clearest everyday example is the JWT, and it is also where the confusion becomes expensive. A JWT has three parts separated by dots. The first two are Base64 encoded JSON, plainly readable by anyone holding the token. Only the third part, the signature, is cryptographic, and it protects integrity rather than confidentiality.
So a JWT is signed, not encrypted. Putting anything private in the payload, an internal user note, an email address, a role you would rather not advertise, is publishing it to whoever holds the token. You can see this for yourself by pasting one into the JWT decoder, which reads the payload without needing any secret at all, because there is no secret to need.
The other half of the same mistake is trusting a JWT you have not verified. Decoding tells you what the token claims. Only checking the signature tells you whether those claims are true, and a decoder deliberately does not do that, because it has no key.
The question to ask, in one line each
Do I need this to survive a channel that mangles bytes? Encoding. No secret involved, and no protection either.
Do I need this unreadable to anyone without a key? Encryption.
Do I need to check a value later without ever storing the value? Hashing.
Do I need to know this came from the right place and was not altered? Signing.
The failure mode this list prevents is always the same shape: reaching for the operation that makes text look scrambled when what you needed was the one that makes it secret. Base64 does the first perfectly and the second not at all, and it never claimed otherwise. The claim was ours.
Questions people ask
No. Base64 is an encoding defined publicly in RFC 4648, with no key involved, and anyone can reverse it instantly. It makes data unreadable to a human glancing at it and offers no protection whatsoever against anyone who wants the contents. If you need something kept secret, you need encryption.
Base64 maps every three bytes onto four characters, so encoded output runs about 33% larger than the input, plus padding. That overhead is the cost of being safe to send through channels that expect text, and it is why embedding large images as data URIs inflates a page more than people expect.
Yes, and that is the point people miss. The header and payload of a JWT are only Base64 encoded, so anyone holding the token can read them. The secret is needed to verify the signature, not to read the contents, which means a JWT payload is public to whoever has the token.
Encryption is two way with a key: the holder can recover the original. Hashing is one way: the original cannot be recovered from the digest at all. Use encryption when you need the data back, and hashing when you only need to check later whether something matches, which is why passwords are hashed rather than encrypted.
Not on its own. SHA-256 is designed to be fast, which is exactly wrong for passwords because it makes guessing cheap for an attacker too. Password storage wants a deliberately slow, salted algorithm such as bcrypt or Argon2. SHA-256 remains an excellent choice for verifying that a file arrived intact.
Only if the decoding happens in your browser. Pasting a live token into a site that sends it to a server hands that token to whoever runs the site, and a JWT is usually a credential. The JWT decoder and Base64 tool here run entirely on your device for that reason.

