Base64URL Encode and Decode Helpers

Encode strings or bytes to unpadded base64url and decode back with strict alphabet, length and fatal UTF-8 validation.

JavascriptAuth Jwt

Code

snippet
export function encodeBase64Url(input) {
  const bytes = toBytes(input);
  let binary = "";
  for (const byte of bytes) binary += String.fromCharCode(byte);
  return btoa(binary).replace(/\+/g, "-").replace(/\//g, "_").replace(/=+$/, "");
}

export function decodeBase64Url(input, options = {}) {
  if (typeof input !== "string") throw new TypeError("input must be a string");
  if (!/^[A-Za-z0-9_-]*$/.test(input)) throw new Error("input contains invalid base64url characters");
  if (input.length % 4 === 1) throw new Error("input has an invalid base64url length");
  const { encoding = "utf-8" } = options;
  const padded =
    input.replace(/-/g, "+").replace(/_/g, "/") + "=".repeat((4 - (input.length % 4)) % 4);
  const binary = atob(padded);
  const bytes = Uint8Array.from(binary, (character) => character.charCodeAt(0));
  return new TextDecoder(encoding, { fatal: true }).decode(bytes);
}

function toBytes(input) {
  if (typeof input === "string") return new TextEncoder().encode(input);
  if (input instanceof Uint8Array) return input;
  throw new TypeError("input must be a string or Uint8Array");
}

const token = encodeBase64Url("user:42");
console.log(token);
console.log(decodeBase64Url(token));
console.log(encodeBase64Url(new Uint8Array([251, 255, 190])));