How Base64 encoding works
Base64 (RFC 4648 §4) exists to move arbitrary bytes through channels that only accept text. It takes three bytes — 24 bits — and re-cuts them into four groups of six bits, each of which indexes a 64-character alphabet: A–Z, a–z, 0–9, + and /. Six bits can name 64 values, which is where the name comes from.
When the input length is not a multiple of three, the last group is padded with = so the output stays a multiple of four: "Man" → TWFu, "Hi" → SGk=, "A" → QQ==. Reading the padding backwards tells you the byte count — one = means the last group carried two bytes, two = means one byte.
Four characters for every three bytes means Base64 always costs about 33 % more than the raw data (exactly ceil(n / 3) × 4 characters, plus any line breaks). That overhead is the price of passing through text-only transports, not a defect.
Text, Unicode and what actually gets encoded
Base64 encodes bytes, never characters, so the text has to become bytes first. This tool always uses UTF-8: "Hello, World!" → SGVsbG8sIFdvcmxkIQ==, and the two Korean syllables "안녕" (six UTF-8 bytes, ec 95 88 eb 8f 85) → 7JWI64WV. A tool that produced something shorter for the same input was not using UTF-8.
This is why btoa("안녕") throws in the console: the classic browser function only accepts characters up to U+00FF, so anything beyond Latin-1 has to go through TextEncoder first. Getting mojibake back from another service usually means it decoded your bytes as Latin-1 or EUC-KR rather than UTF-8.
When decoded bytes are not valid UTF-8 text, we do not guess. The result switches to a byte inspector: a magic-number guess at the file type (PNG, JPEG, GIF, PDF, ZIP, gzip, WebP, MP4, ELF) and a hex dump of the first 256 bytes, with a "Download as file" button.
Standard, URL-safe and MIME line wrapping
The + and / of the standard alphabet are unsafe in URLs and filenames: + becomes a space in form-encoded query strings and / splits a path. RFC 4648 §5 defines Base64URL, which swaps them for - and _ and usually drops the = padding. JWTs, WebAuthn and OAuth PKCE all use this variant.
Line wrapping is the other historical split. MIME (RFC 2045) requires lines of at most 76 characters, while PEM certificates and OpenSSH keys wrap at 64. Pick the matching width when you are pasting into a mail header or a .pem file; leave wrapping off for a value that goes into JSON, a header or an environment variable.
Decoding is deliberately forgiving in the other direction: we strip whitespace, accept both alphabets, and re-pad short input before decoding, because copied Base64 almost always arrives with newlines or a missing tail.
Data URLs: when to inline an image
A data URL (RFC 2397) carries the file inside the reference itself: data:image/png;base64,iVBORw0KGgo… Tick the "data: prefix" box and we build one with the MIME type of the file you dropped; paste one in and we strip the prefix, remember the type and offer the decoded bytes back as a file.
Inlining removes one HTTP request, which is worth it for a tiny icon, an email signature image or a CSS background of a few hundred bytes. Beyond roughly 5–10 KB it usually costs more than it saves: the asset is 33 % larger, it is re-sent with every copy of the document, and it can no longer be cached, preloaded or served by a CDN on its own.
Decoding a JWT
A JSON Web Token (RFC 7519) is three Base64URL segments joined by dots: header, payload and signature. Paste one and we detect the shape, decode the first two and show them separately — useful for reading exp, iat, iss and your own claims when a request is being rejected.
Decoding is not verifying. The header and payload of a JWT are encoded, never encrypted — anyone holding the token can read every claim in it. Only the signature proves the token was not altered, and checking it requires the secret or public key, which belongs on your server and not in a web page. Never put a personal identifier or anything confidential in a JWT payload.
When decoding fails
Two failures cover nearly everything. A character outside the alphabet — we name it and give its position — usually means the value was truncated by a log line, wrapped by a mail client, or is URL-encoded rather than Base64 (%2B where a + should be: decode the percent-encoding first, with the URL Encoder).
The other is an impossible length: after padding is removed, a Base64 string can never leave a remainder of 1 when divided by 4, because no number of bytes produces a single leftover character. That result means characters are missing, not that the padding is wrong.
If the decode succeeds but the text looks wrong, the bytes are fine and the character set is not: check whether the producer encoded UTF-8 or a legacy code page before blaming the Base64.
Base64 is encoding, not encryption
Base64 has no key and no secret. Anything encoded with it can be decoded by anyone, in one step, on this page. It is a transport format — safe for embedding binary in JSON, email or a data URL, and useless as protection. A Base64 string in a config file or a request body is plaintext with extra steps.
HTTP Basic authentication is the classic illustration: the Authorization header is base64(user:password), which is why the scheme is only acceptable over TLS. If you need secrecy, encrypt first and Base64 the ciphertext — in that order.
All of that happens here, in this tab: text and files are read with the browser’s File API and encoded locally, so a private key or an access token you paste never reaches a network at all.