Open any site's JavaScript bundle, find a string that ends in "=", and you've probably found someone's "encrypted" API key
I've seen this pattern in real code reviews more than once: a developer needs to put a key in frontend code, feels uneasy about it being plain text, and runs it through btoa() before committing. It looks different now — Sk1QVV9BUElfS0VZXzRiNzQy... instead of the raw string — so it feels safer. It isn't. Decoding it back takes one line: atob('Sk1QVV9BUElfS0VZXzRiNzQy...'), no password, no key, no brute force. Anyone with DevTools open can do it in under a second.
There are exactly 3 ways to transform data, and only 1 keeps it secret
1. Encoding (Base64, Hex, URL encoding) — reversible by anyone
Encoding solves a transport problem, not a security one: binary data can't travel safely over text protocols like HTTP or sit reliably inside JSON, so Base64 maps it into a safe ASCII alphabet. There's no key involved — the algorithm is public, taught in every intro CS course, and reversing it needs nothing but the string itself.
const key = 'MY_SECRET_API_KEY_12345';
const encoded = btoa(key);
// 'TVlfU0VDUkVUX0FQSV9LRVlfMTIzNDU='
const decoded = atob(encoded);
// back to 'MY_SECRET_API_KEY_12345' -- one function call, no secret needed2. Hashing (SHA-256, bcrypt) — one-way, but not a hiding place either
Hashing exists for verification: hash a password before storing it, then compare hashes at login instead of storing the plaintext. A hash can't be mathematically reversed, but that's not the same as "safe to expose" — an unsalted hash of a short or predictable value (like an API key with a known format) can often be found in a rainbow table, a precomputed lookup of common inputs and their hashes. Hashing an API key doesn't hide it; it just changes the attack from "read it" to "look it up."
3. Encryption (AES-256, RSA-2048) — the only one that actually keeps a secret
Encryption combines an algorithm with a secret key you control. Without that key, the ciphertext is computationally infeasible to reverse. The test that separates all 3: if a stranger can reverse your transformation without a password, it's encoding, not encryption — no exceptions.
The mistake that compounds the first one
Once a developer realizes Base64 "isn't safe," a common next move is pasting the value into an online encoder or decoder to double-check it — and now the actual raw secret, not the encoded version, is sitting in a request to a server you don't control. Debugging a JWT the same way is worse: a JWT is just 3 Base64 segments joined by dots (header, payload, signature), and a live session token pasted into a cloud JWT decoder is a live session token now sitting in someone else's request logs.
SolveBar's Base64 Encoder/Decoder avoids this specific trap: I checked the source, and both directions run through btoa()/atob() — functions that have shipped in every browser for over 20 years — wrapped with encodeURIComponent/decodeURIComponent for Unicode safety, directly in the page, with no fetch() call anywhere in the conversion path. Open the Network tab while using it and you'll see 0 outbound requests, the same way you would with our Hash Generator or JWT Decoder. All 3 tools share the same rule: 0 network calls in the conversion path.
What actually protects an API key
No amount of encoding fixes a key that shouldn't be in frontend code at all. The real architecture: keys with write access stay server-side, and the frontend calls your own backend, which attaches the key and proxies the request — the browser never sees it in any form, encoded or not. For read-only or public-tier keys that must ship to the browser, treat them as public by design (rate-limited, scoped, rotatable) rather than "hidden." And keep .env files out of Git entirely via .gitignore, rather than debugging them by pasting them into a cloud converter.