Base64 with TextEncoder/TextDecoder


I’ve written more base64 encoders and decoders than I care to remember over the years.

atob() and btoa() are awful APIs. Their binary representation is packed into a string which has to be extracted using .charCodeAt(). While btoa() might be fixed by having it accept a BufferSource, and maybe atob() might be redeemed by adding an extra parameter, I think that the encoding API is a more natural fit.

Imagine this as a 6-bit per-symbol encoding of a limited subset of the full character space (i.e., only 64 different code points are recognized and encoded correctly).

What is perhaps strange about this is that you would use a decoder to encode and an encoder to decode in the classic sense:

// 'A' is the encoded form, but we use a decoder to produce it.
console.log(new TextDecoder('base64').decode(new Uint8Array([0]))); // -> 'A'
console.log(new TextEncoder('base64').encode('A')); // -> 0

Maybe that enough of a reason that this isn’t quite the right idea. I’m also happy to patch atob() and btoa(), but this seems like a better fit.

Edit: Forgot some of the rationale: While it is relatively easy to do base64 yourself, few implementations do this well. In particular, with WebCrypto, there is greater need for constant-time encodings of binary data and I’m not aware of any of those. The Firefox btoa() implementation almost certainly isn’t constant time.

Interest and use cases for transcoding streams

This has been suggested multiple times - in fact, when I was first proposing the Encoding API it supported base64. Consensus was to remove it since it was out of scope (it’s not a “text encoding”) and also the encoding-with-a-decoder/decoding-with-an-encoder confusion. I tripped myself up several times on it and I’d written the spec. :frowning:

That said, I think there’s pretty broad agreement that a BufferSource :left_right_arrow: base64 DOMString API would be useful if we can come up with a sensible place to put it. Past discussions have usually ended with “can we just wedge it into btoa/atob somehow?” and the proposer lost interest in figuring out if that was possible or not. So I’d follow that track if possible.


atob and btoa aren’t feasible I think. You would need to have a signal that would allow you to have atob return an ArrayBuffer. It’s unlikely that would be backwardly compatible.