Base64 with TextEncoder/TextDecoder


#1

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
#2

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.


#3

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.