Encoding, not encryption
Base64 is a way of representing arbitrary binary data using only 64 printable ASCII characters. It exists because many systems — email headers, URLs, JSON string fields, XML documents — were designed for text and mangle or reject raw bytes. Encoding guarantees safe passage through them.
It provides no confidentiality whatsoever. There is no key, and decoding requires nothing but the algorithm, which every language implements in its standard library. Treating a Base64 string as obscured is a recurring and serious mistake: credentials Base64-encoded in a configuration file or an HTTP header are, for practical purposes, in plain text. HTTP Basic authentication encodes the username and password this way, which is precisely why it is only acceptable over TLS.
The mechanics are simple: three bytes of input, 24 bits, are regrouped into four 6-bit values, each mapped to a character. Because output is always a multiple of four characters, input that is not a multiple of three is padded with one or two = signs. This produces a consistent 33 percent size increase, which matters when embedding large assets.
The URL-safe variant and why it exists
Standard Base64 uses + and / as its final two characters, and both have reserved meanings in URLs — + historically decodes to a space in query strings, and / is a path separator. A Base64 string dropped into a URL therefore corrupts on the way through.
RFC 4648 defines a URL-safe alphabet substituting - and _ for those two characters. Everything else is identical, so converting between the variants is a two-character replacement. Padding is frequently omitted as well, since = also requires escaping, and the decoder can infer the original length.
This is the variant used by JWTs, which is why a token's segments contain hyphens and underscores but never plus or slash. If a decoder rejects a token, feeding it standard Base64 when it expects URL-safe — or the reverse — is the usual cause.
Data URIs and when embedding pays off
A data URI embeds a file directly in a document as data:image/png;base64,..., eliminating a network request. For small assets this can be worthwhile: a tiny icon inlined into CSS avoids a round trip that might cost more than the bytes.
The trade-offs are real, though. The 33 percent size penalty applies, embedded resources cannot be cached separately so they are re-downloaded with every change to the containing file, and large Base64 blobs inside CSS or JavaScript delay parsing of that file. Content Security Policy also frequently blocks data: URIs, since they are a known vector for injecting content.
The practical guidance is to inline only genuinely small assets — a few kilobytes at most — and only where the request overhead is a measurable share of the cost. With HTTP/2 and HTTP/3 multiplexing, the per-request penalty that originally justified inlining is much smaller than it was, so the technique matters far less than it did.