Skip to content
Encoding2026-10-11Begin5 min read

Base64 vs Base64URL: Padding, JWT Segments, and PEM Line Wraps

Symptom: “looks like Base64” but every decoder disagrees

You paste a JWT segment into a generic Base64 box and get garbage, or a PEM blob fails after someone “cleaned” the newlines. The bytes were never wrong — the dialect was. Standard Base64 (RFC 4648 §4), Base64URL (RFC 4648 §5 / JWT), and PEM (RFC 7468) all speak Base64-shaped text, but they disagree on two characters, on = padding, and on whether whitespace is allowed.

Use the on-site Base64 encoder/decoder with the URL-safe toggle when you need a round-trip, the JWT decoder when the string has two dots, and the certificate decoder when you see BEGIN CERTIFICATE.

Alphabet and padding in one table

RuleStandard Base64Base64URL (JWT)PEM body
Char 62 / 63+ / /- / _+ / /
Trailing =Usually presentUsually strippedPresent as needed
WhitespaceOften rejected or ignoredNot part of the tokenRequired as 64-char lines
Typical homeMIME, data URIs, APIsheader.payload.signatureCertificates / keys

Conversion is mechanical:

  • Standard → URL-safe: +→-, /→_, drop =
  • URL-safe → standard: reverse the two characters, then pad length to a multiple of 4 with =

Length after decode depends on the byte length, not on whether padding characters were written. Missing = is not corruption if the alphabet and length math still line up; it is a transport preference.

Why JWT refuses +, /, and =

A compact JWT is three Base64URL segments joined by .:

base64url(header) + "." + base64url(payload) + "." + base64url(signature)

Putting that string into a query parameter or Authorization header must not introduce characters that URL parsers treat specially. + can become a space in application/x-www-form-urlencoded. / splits path segments. = starts query values. Base64URL removes those landmines so the token travels as one opaque string.

Important consequences for debugging:

  1. Decode one segment at a time with a Base64URL-aware tool — or toggle URL-safe on the Base64 page. Feeding the whole a.b.c string into a MIME Base64 decoder will fail because of the dots.
  2. Header and payload decode to JSON text. Signature bytes are opaque binary; expecting readable JSON there is a category error.
  3. JWT is not encryption. Base64URL only hides structure from casual eyeballing. Anyone with the token can read claims. See the JWT decode guide and exp/nbf clock skew for claim semantics after you can see the JSON.

Padding traps that look like “invalid token”

Libraries disagree on whether to re-add = before calling atob / b64decode. Patterns that burn hours:

  • Proxy stripped = from a standard Base64 field in a header. Local curl still had padding; the gateway did not.
  • One side URL-safe, the other standard. Signature verification fails even when the secret is correct — the signing input string no longer matches. Related: JWT signature invalid.
  • Manual “fix” that adds == to a Base64URL segment that already decoded fine. Extra padding of the wrong length throws; correct padding is '', '=', or '==' so that len % 4 === 0.

Quick check: for a URL-safe segment s, compute pad = (4 - (s.length % 4)) % 4, append that many =, map -_ back to +/, then decode. If that works and the JSON looks sane, the original token was fine — your first decoder was not Base64URL-aware.

PEM: same alphabet as standard Base64, different packaging

PEM wraps DER (binary ASN.1) as:

-----BEGIN CERTIFICATE-----
<Base64 lines, typically 64 columns>
-----END CERTIFICATE-----

Compared with JWT:

ConcernJWT segmentPEM body
AlphabetBase64URLStandard Base64
Line breaksForbidden inside a segmentExpected every ~64 chars
FramingDots between three partsBEGIN/END labels
After decodeJSON or raw sig bytesDER certificate / key

Common PEM failures that are not crypto bugs:

  • Someone joined all lines into one mega-line and a strict consumer still accepts it — another rejects it. Prefer keeping RFC-style wrapping when pasting into configs.
  • Copy/paste introduced a UTF-8 BOM or smart quotes around the labels.
  • Only the leaf was pasted when the server needs leaf + intermediates (a chain problem, not a Base64 problem). Walk incomplete chain troubleshooting and the certificate decoder guide.

OpenSSL’s mental model stays useful: decode PEM → DER bytes → parse fields. The on-site certificate tool answers “what does this PEM say?”; it does not replace openssl verify for trust.

Decision tree: which tool first?

  1. String has two dots and three chunks → JWT decoder. Do not MIME-decode the whole token.
  2. String has BEGIN … / END … → certificate decoder (or key tooling). Preserve newlines.
  3. Alphabet contains - or _ and no PEM labels → treat as Base64URL; use URL-safe mode on Base64.
  4. Alphabet is +/ with optional = → standard Base64 (API fields, data URIs, many crypto libraries).
  5. Output looks like Chinese mojibake after a successful decode → charset mismatch (UTF-8 vs GBK), not alphabet mismatch. See Base64 Chinese garbled.

Implementer's note

ToolVault’s Base64 page maps UTF-8 text through TextEncoder / TextDecoder, then applies the selected alphabet and padding rules. URL-safe mode only remaps characters and padding — it does not change Unicode handling. JWT decoding is a separate path: split on ., Base64URL-decode each segment, lossless-parse JSON claims (large integers stay readable). Certificate decoding strips PEM labels, ignores internal whitespace, Base64-decodes to DER, then walks a browser-side ASN.1 subset. None of these paths upload your material.

Five-minute checklist

  1. Count dots: zero (blob), two (JWT), or PEM labels?
  2. Inspect characters 62/63: +/ or -_?
  3. Is = missing on purpose (JWT) or stripped by a proxy (bug)?
  4. For PEM: are line breaks and BEGIN/END labels intact?
  5. After bytes decode cleanly, is the remaining failure JSON claims, signature crypto, or TLS trust?

This article is brought to you by ToolVault. More developer tools at the homepage.