Base64, URL Encoding and JWTs: What They Are (and Why They're Not Encryption)

Base64, URL encoding and JWTs all turn readable text into something that looks scrambled, so people often assume they're secret. None of them is encryption: anyone can reverse them in a second. Here's what each one is for, with worked examples you can check yourself.

Base64: packaging data as safe text

Base64 turns any bytes into a string built from 64 characters that survive email systems, JSON and HTML: A to Z, a to z, 0 to 9, + and /, with = as padding at the end. Every 3 bytes become 4 characters, so the result is about a third bigger than the original. The rules are in RFC 4648.

TextBase64
HiSGk=
DubaiRHViYWk=
caféY2Fmw6k=
user:passdXNlcjpwYXNz

"café" needs more characters than you might expect because é takes 2 bytes in UTF-8. The last row is how HTTP Basic authentication sends a username and password, which is why Basic authentication must only ever be used over HTTPS: anyone who sees that header can decode it instantly.

There is also a variant called base64url, which swaps + for - and / for _ so the result is safe inside web addresses. Padding is often dropped. JWTs use this variant.

URL encoding: making text safe inside a link

Some characters have a job in a web address: ? starts the query, & separates parameters, # starts a fragment. To use them as ordinary text, you percent-encode them: each byte becomes % followed by two hexadecimal digits, as defined in RFC 3986.

  • A space becomes %20, & becomes %26, = becomes %3D, + becomes %2B and % itself becomes %25.
  • The search "Al Barsha & Jumeirah" becomes Al%20Barsha%20%26%20Jumeirah. Left unencoded, the & would split it into two parameters and the search would only see "Al Barsha".
  • Non-English text is encoded byte by byte in UTF-8: "مرحبا" becomes %D9%85%D8%B1%D8%AD%D8%A8%D8%A7, two bytes per Arabic letter.

Encode the individual values, not the whole address. Encoding a full URL turns https:// into https%3A%2F%2F and breaks it. Also note that web forms traditionally send a space as + rather than %20, as MDN's reference explains, so you'll see both in the wild.

JWTs: three base64url parts joined by dots

A JSON Web Token, defined in RFC 7519, is a compact way for a server to hand you a signed statement such as "this is user 1234 and they may view reports". It has three parts separated by dots: header.payload.signature. Here is a real token, split into its parts for readability and signed with a made-up key:

  1. Header: eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9
  2. Payload: eyJzdWIiOiIxMjM0NTY3ODkwIiwibmFtZSI6IlNhcmEiLCJyb2xlIjoidmlld2VyIiwiaWF0IjoxNzkwMDAwMDAwLCJleHAiOjE3OTAwMDM2MDB9
  3. Signature: wfEdMdRnWXrFLpWPEH2B0Np9vYEnku8nXaZY6tkm06E

Decoding the first two parts gives plain JSON:

  • Header: {"alg":"HS256","typ":"JWT"}, which names the signing algorithm.
  • Payload: {"sub":"1234567890","name":"Sara","role":"viewer","iat":1790000000,"exp":1790003600}, the claims.

The signature is calculated from the header and payload using a secret key (for HS256) or a private key (for algorithms such as RS256 and ES256). It is the only part that proves anything. Most JWTs start with eyJ, because that's how the start of a JSON object, {" followed by a letter, looks in Base64.

Reading exp, iat and nbf

JWT times are NumericDates: the number of seconds since 1 January 1970 UTC.

  • iat (issued at): 1790000000 is 21 September 2026, 14:13:20 UTC, which is 18:13:20 in the UAE (UTC+4).
  • exp (expires): 1790003600 is 3,600 seconds later, so this token is valid for one hour and must be rejected from 15:13:20 UTC.
  • nbf (not before): the token must not be accepted before this time.

The standard lets servers allow a small leeway, usually no more than a few minutes, for clocks that disagree. Once exp has passed, the server rejects the token, typically with a 401 error, which is why an app that worked in the morning can fail in the afternoon. To turn a timestamp into a date, run new Date(1790000000 * 1000).toISOString() in your browser's console, or date -u -d @1790000000 on Linux (date -u -r 1790000000 on macOS). A 13-digit value is in milliseconds, which isn't what the standard specifies, so something upstream has probably got it wrong.

Decoding is not verifying, so guard your tokens

Anyone holding a JWT can read its payload, so never put secrets in one. Anyone can also edit the payload, changing "viewer" to "admin", and re-encode it. What stops that working is the server checking the signature with its key, accepting only the algorithms it expects, and checking exp, nbf, the issuer and the audience. RFC 8725, the JWT best-practice document, describes libraries that accepted tokens with the algorithm set to "none" and so checked no signature at all.

A decoder shows what a token claims, not whether it's genuine. Encrypted JWTs (JWE) are different: they have five parts, and their contents can't be read without the key.

Be careful where you paste tokens, too. A valid access token works like a temporary password: whoever holds it can act as you until it expires. Pasting one into an online decoder that sends it to a server hands it over. Use a decoder that works locally, or test with an expired token. Treat tokens like passwords in tickets, screenshots and chat messages too. If one leaks, sign out of that session or ask the administrator to revoke it.

Using our tools

  • Base64 Encoder: encodes and decodes UTF-8 text with the standard alphabet. It works on text, not files or images. A base64url string containing - or _ shows "Invalid Base64", so swap them for + and / first, or use the JWT Decoder.
  • URL Encoder: encodes a single value the way browsers' encodeURIComponent does, leaving letters, digits and a few marks such as -, _, . and ~ unchanged. When decoding, it doesn't turn + into a space.
  • JWT Decoder: shows the header and payload as formatted JSON, plus the signature string, entirely in your browser, so the token isn't sent anywhere. Remove any "Bearer " prefix before pasting. It does not verify the signature and it doesn't convert exp or iat into dates, so use the method above. It only reads three-part signed tokens, not five-part encrypted ones.

JWT payloads are JSON, so our JSON guide helps with reading them, and our guide to hashes covers SHA-256, the hash inside HS256.

Frequently asked questions

Is Base64 a form of encryption?

No. It uses no key, and anyone can decode it instantly. RFC 4648 itself notes that it hides data from a casual glance but gives no confidentiality.

Can I change the data in a JWT?

You can edit and re-encode the payload, but the signature will no longer match, and a correctly configured server rejects the token.

What's the difference between %20 and + for spaces?

%20 is standard percent-encoding and means a space anywhere in a URL. + means a space only in form-style query strings; elsewhere it's a literal plus sign, which is why a real plus in a value must be sent as %2B.

Why do JWTs expire so quickly?

Because a stolen token works until it expires, short lifetimes limit the damage. Apps usually get a fresh one in the background with a separate refresh token.

More guides