1 minute read

URL friendly data encoding is important when working with data URIs and APIs that work with binary formatted data. base64url is a modification of the base64 encoding that replaces the problematic characters of base64 for URLs. This means swapping ‘+’ for ‘-‘ and ‘/’ for ‘_’, as well as removing the trailing ‘===’ padding.

I found myself needing a concise and dependency free base64url encode/decoder that leverages the native base64 encoding functions. The following is a mix of my own design and elements from numerous alternative solutions from across the internet. There are a number of libraries published to NPM that accomplish this but sometimes adding a dependency adds complexity and risk.

function base64url_encode(buffer: ArrayBuffer): string {
    return btoa(Array.from(new Uint8Array(buffer), b => String.fromCharCode(b)).join(''))
        .replace(/\+/g, '-')
        .replace(/\//g, '_')
        .replace(/=+$/, '');
}

function base64url_decode(value: string): ArrayBuffer {
    const m = value.length % 4;
    return Uint8Array.from(atob(
        value.replace(/-/g, '+')
            .replace(/_/g, '/')
            .padEnd(value.length + (m === 0 ? 0 : 4 - m), '=')
    ), c => c.charCodeAt(0)).buffer
}

Things to note about this implementation are:

  • base64url_decode() will return an ArrayBuffer that is read only. Use buffer.slice(0) to make a writable copy.
  • The replaceAll and padEnd functions used may require polyfills if you intend to target Internet Explorer.
  • replaceAll was chosen in place of replace(regex,) as it should be faster than the overhead of the regex engine.