Base64, decoded
The most common encoding you will meet, the most commonly misread, and the one people most often mistake for a security measure.
Base64 exists to move arbitrary bytes through channels that only accept text: e-mail bodies, JSON strings, HTTP headers, XML documents, URLs. It takes three bytes at a time, splits those 24 bits into four six-bit groups, and writes each group as one of 64 printable characters. Three bytes in, four characters out — which is why base64 output is always about a third larger than what went in, and why base64 payloads are so often compressed first.
It is not encryption. There is no key, and no secret is needed to reverse it. A base64 string in a cookie, a URL, or a config file is visible data, and should be treated that way by everyone who handles it.
Paste a base64 string into the decoder →The two alphabets
| Variant | Value 62 | Value 63 | Padding | Where you see it |
|---|---|---|---|---|
| Standard (RFC 4648 §4) | + | / | = to a multiple of 4 | MIME, HTTP Basic auth, PEM certificates, data: URIs |
| URL-safe (RFC 4648 §5) | - | _ | usually omitted | JWTs, WebAuthn, filenames, query-string parameters |
A string that contains both +/ and -_ is not base64
of either kind — that mixture is a reliable "this is something else" signal, and the
decoder here rejects it outright rather than guessing.
Recognising it
There is no syntactic test. password is a perfectly valid base64 string:
eight characters from the alphabet, length divisible by four. It decodes to six bytes
of noise. So does every other lowercase word of the right length. This is exactly why
naïve "auto-detect base64" tools produce nonsense — they check the characters and stop.
The signals that actually work, in order of strength:
- Decode it and look. Real base64 produces text, a recognisable file
signature, or structured data.
1f 8bis gzip,PKis a zip,%PDFis a PDF,{is JSON. Noise means it was not base64. - Trailing
=. Padding is a deliberate act by an encoder; no English word ends in one. It also tells you the input length mod 3. - Mixed case with digits, no spaces, length a multiple of four. Weak on its own, useful in combination.
- Context. The header is called
Authorization: Basic, the field is calledstate, the value came out of adata:URI.
Where it hides things
- HTTP Basic authentication.
Authorization: Basic dXNlcjpwYXNzd29yZA==isuser:password— the credentials are not obscured in any meaningful sense, which is why Basic auth over plaintext HTTP is credential disclosure. - JWTs. Three base64url segments separated by dots. The claims are readable by everyone who touches the token; the signature only stops them being changed. See the JWT page.
- SAML. Assertions are base64, and in the HTTP-Redirect binding they are raw-deflate compressed underneath — an encoding that cannot be detected by inspection, so you have to ask for it.
-
data:URIs.data:text/html;base64,…carries a whole document, with its own origin. That is whydata:in a CSPscript-srcis close to'unsafe-inline'— see the CSP builder. - Exfiltration and droppers. Base64 turns binary into something that passes a content filter looking for executables, and into something that fits in a DNS label or a URL parameter.
Nesting
Base64 is rarely the last layer. The shape that turns up over and over is
base64 of gzip of JSON: something was too big for a cookie or a query
parameter, so it was compressed, and compression produces bytes, so it was encoded. The
decoder unwraps all three without being told, because each layer
leaves evidence the next step can check — gzip's 1f 8b magic, then JSON's
opening brace.
Double base64 is also common, and is usually a bug rather than an intention: two systems each helpfully encoding the same field. If a decoded value still looks like base64, it probably is.
Open the decoder →