Stateless Tools

They exist for different reasons

Base64 carries binary through text

It exists to move non-character data — images, encrypted bytes — through channels that only handle text, such as mail bodies, JSON strings and HTTP headers. Three bytes become four characters, so the result grows by about 33%.

URL encoding protects delimiters

In a URL, ?, &, = and / are structural. When a value contains them the structure breaks, so they become forms like %26 to mark them as data. Only the substituted characters grow.

Neither substitutes for the other

Base64 output contains + and /, both meaningful in URLs. Conversely URL encoding cannot turn binary into text. Their purposes do not overlap, so you choose by situation — and sometimes you need both.

Keep the Base64 encoder/decoder and URL encoder/decoder open if you want to try values as you read.

The classic failure: plus becomes space

This happens when a Base64 value goes straight into a URL query. It reproduces inconsistently, which makes it slow to diagnose.

What happens

In HTML form encoding (application/x-www-form-urlencoded), + means space. So when a server parses ?token=aGVsbG8+d29ybGQ=, the plus becomes a space, yielding aGVsbG8 d29ybGQ=. Base64 decoding then fails — or worse, returns the wrong bytes.

Why only some values break

If the Base64 output happens to contain no +, nothing goes wrong. It only breaks when the input data produces one. Hence "it worked in testing but fails for certain users in production". / and = can likewise be mistaken for a path separator and a query delimiter.

URL-safe Base64 is the fix

A variant replacing + with - and / with _ (RFC 4648), usually dropping the = padding. This is exactly what JWT uses. Enable the URL-safe option in the Base64 tool to produce it.

Or URL-encode the Base64 once more

If you must keep standard Base64, URL-encode its output so + becomes %2B. The receiver must then URL-decode first and Base64-decode second — and if that order is not written down, the next person will get it wrong.

Double encoding and %25

Seeing %25 means it was encoded twice

% itself URL-encodes to %25, so encoding an already-encoded %20 again produces %2520. A %25 in a URL usually means the framework and your own code both encoded it.

Redirect parameters are the usual site

As in ?next=/login?from=home, where a URL contains a URL. The inner URL must be encoded exactly once and not again. This is a common cause of broken post-login redirects. Paste it into the parameter table of the URL tool to see how far it has been decoded.

Decode exactly once

"It did not decode, so decode again" is dangerous. If user input deliberately contains a double-encoded value such as %2527, code that decodes twice produces a quote character after the filter has already run. A mismatch between filtering and decode count is itself a vulnerability.

Why non-Latin text and emoji get so long

You get three chunks like %EC%95%88

URL encoding encodes bytes, not characters. The Korean syllable "안" is three bytes in UTF-8 (EC 95 88), so it becomes %EC%95%88 — one character expanding to nine. Emoji are four bytes, giving twelve characters such as %F0%9F%98%80.

A different pre-encoding charset breaks it

The same syllable in EUC-KR is two bytes, giving %BE%C8. If the sender assumes UTF-8 and the receiver assumes EUC-KR, the text is corrupted. This arises when integrating with older systems, and it is a problem in the preceding step, not in URL encoding itself.

Base64 works the same way

Base64 also operates on bytes. To Base64 a string you must first convert it to bytes, and the charset you choose changes the result. Defaults differ by language, so when exchanging values between systems, specify "UTF-8, then Base64" explicitly.

encodeURI versus encodeURIComponent

A frequent JavaScript mistake. encodeURI assumes you are encoding a whole URL and leaves ?, & and / alone. encodeURIComponent assumes a single value and encodes everything. Always use the latter for query parameter values, or an & inside the value will be read as a parameter separator.

In summary

  1. Base64 to carry binary through a text channel; URL encoding to preserve URL structure.
  2. Putting Base64 in a URL means using the URL-safe variant or URL-encoding it once. Pasted raw, + becomes a space.
  3. %25 means double encoding. Encode once, decode once.
  4. Both operate on bytes, so the charset you converted to beforehand changes the result.
  5. In JavaScript, use encodeURIComponent for query values.
  6. Neither is encryption. Anyone can reverse them.

Next: try the URL-safe option in the Base64 encoder/decoder, use the parameter table in the URL encoder/decoder to see how far a value is decoded, and see URL-safe Base64 in practice in the JWT decoder.