How to Decode Base64 Strings (and JWT Payloads)

Base64 is reversible encoding, not encryption. Decode it in one step, handle Unicode correctly, and read JWT sections that use Base64url.

What Base64 Actually Is

Per RFC 4648, Base64 maps arbitrary binary data to 64 printable ASCII characters (A-Z, a-z, 0-9, +, /) using 3-byte → 4-character groups, with = padding to fill out the final group. It is fully reversible with no key, so it is encoding, not encryption — never use it to hide secrets. See also the Base64 encoding is not encryption blog post for the deeper explainer.

The Base64 tool does the encode / decode round trip in your browser.

Decoding and Encoding

In the browser, use btoa to encode and atob to decode — but both only handle Latin-1 bytes. For non-ASCII text, round-trip through UTF-8 so characters like é, ü, or survive:

// Encode UTF-8 string → Base64
const encoded = btoa(
  String.fromCharCode(...new TextEncoder().encode('Ada Lovelace 你好'))
);
// → "QWRhIExvdmVsYWNlIOS9oOWlvQ=="

// Decode Base64 → UTF-8 string
const decoded = new TextDecoder().decode(
  Uint8Array.from(atob(encoded), c => c.charCodeAt(0))
);
// → "Ada Lovelace 你好"

Without the TextEncoder / TextDecoder round trip, multi-byte characters get garbled — atob interprets every Base64-decoded byte as a Latin-1 codepoint, which is wrong for anything outside ASCII.

Base64 vs Base64url

Two variants of the same encoding, picked for different contexts:

Feature Standard Base64 Base64url
Spec RFC 4648 §4 RFC 4648 §5
Character 62 + -
Character 63 / _
Padding = (required) Often omitted
Safe in URLs / filenames No (+ and / need escaping) Yes
Used by MIME, email attachments JWT, OAuth tokens, JWS / JWE

atob does not accept Base64url directly — convert first by replacing -+, _/, and padding the length up to a multiple of 4 with =:

function base64urlToBase64(input) {
  let b64 = input.replace(/-/g, '+').replace(/_/g, '/');
  while (b64.length % 4) b64 += '=';
  return b64;
}

Reading a JWT

A JWT (per RFC 7519) is three Base64url sections joined by dots: header, payload, and signature:

eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiIxMjM0NSIsIm5hbWUiOiJBZGEiLCJpYXQiOjE3MTY4MDAwMDB9.cF8wq...
└──────── header ───────────┘ └─────────── payload ────────────┘ └─ signature ─┘

Decoding the first two sections reveals the claims; the signature is binary and is not meant to be human-readable. The JWT decode tool does the split + decode in one click. In code:

function decodeJwt(token) {
  const [headerB64, payloadB64] = token.split('.');
  const header  = JSON.parse(atob(base64urlToBase64(headerB64)));
  const payload = JSON.parse(atob(base64urlToBase64(payloadB64)));
  return { header, payload };
}

For the deeper walk-through, see the How to decode a JWT blog post.

Decoding Is Not the Same as Verifying

Decoding a JWT reveals the claims but says nothing about authenticity. Anyone can forge a token whose payload says "role":"admin"; only the signature, verified against the issuer's key, proves the token is real. Never make a trust decision on an unverified token — decode for inspection, debugging, and display only.

Common JWT Claims

The registered claims defined by RFC 7519 §4.1 — these names are reserved across all JWT-using systems:

Claim Meaning Notes
iss Issuer The system that minted the token
sub Subject Usually the user ID
aud Audience The intended recipient — always check this server-side to prevent token reuse across services
exp Expiration Unix seconds — always check before trusting any claim
nbf Not Before Unix seconds — token is invalid until this time
iat Issued At Unix seconds when the token was minted
jti JWT ID Unique identifier for revocation lists

Custom claims live alongside these (e.g. role, tenant_id). Always validate exp and aud on the server, not just on the client.

See also

This guide covers Base64 + JWT decoding. For the JWT-specific tool, see JWT Decode; for the deeper "why Base64 isn't security" explainer, see Base64 encoding is not encryption.

Sources

  • RFC 4648 — The Base16, Base32, and Base64 Data Encodings
  • RFC 7519 — JSON Web Token (JWT)
  • MDN — btoa and atob (the browser Base64 primitives, ASCII-only)
  • MDN — TextEncoder (the UTF-8 round-trip helper)

Last reviewed June 2026.