Skip to content

Basic Auth Generator — JavaScript source

Build HTTP Basic Access Authentication headers from a username and password, or decode an existing Authorization header back to its credentials. UTF-8 safe and fully client-side, with a shareable link.

This is the JavaScript implementation — the same logic the interactive tool runs, in a shareable, citable form.

/**
 * basic-auth-generator - HTTP Basic-Auth header encode/decode.
 *
 * Language:   JavaScript (ES2020+, runs unmodified in Node 16+ and modern browsers)
 * Source:     CosmoDev polyglot showcase port of the Basic Auth Generator tool,
 *             ported from src/lib/basic-auth.ts (the canonical TypeScript
 *             implementation) and kept in lock-step with cli/basic-auth-generator.
 * License:    display source - part of CosmoDev's polyglot tool pages.
 *
 * Design goals:
 *   - Pure + deterministic; never throws (parse returns null on malformed input).
 *   - Functionally equivalent to the TS reference + Go twin: same inputs ->
 *     same outputs, same reject behavior on malformed headers.
 *   - Self-contained: stdlib only (no npm dependencies).
 *
 * The TS source delegates to UTF-8-safe base64 helpers (src/lib/base64.ts)
 * built on TextEncoder/TextDecoder + btoa/atob. We inline the same two helpers
 * here so the port stays single-file and handles multibyte credentials
 * (`café:päss`) correctly - btoa alone throws on code points above U+00FF.
 */

'use strict';

/**
 * A parsed username/password pair.
 * @typedef {Object} BasicAuthCredentials
 * @property {string} user
 * @property {string} pass
 */

/**
 * UTF-8 safe base64 encode. Mirrors b64encode() in src/lib/base64.ts: encode
 * to UTF-8 bytes, rebuild a binary string, then btoa. Iterating (rather than
 * spreading into fromCharCode) avoids the call-stack limit on long inputs.
 *
 * @param {string} str
 * @returns {string}
 */
function b64encode(str) {
  const bytes = new TextEncoder().encode(str);
  let bin = '';
  for (const b of bytes) bin += String.fromCharCode(b);
  return btoa(bin);
}

/**
 * UTF-8 safe base64 decode. Mirrors b64decode() in src/lib/base64.ts: strip
 * embedded whitespace, atob back to a binary string, then decode the bytes as
 * UTF-8. Throws on an invalid token; the caller maps that to null.
 *
 * @param {string} b64
 * @returns {string}
 */
function b64decode(b64) {
  const bin = atob(b64.replace(/\s+/g, ''));
  const bytes = new Uint8Array(bin.length);
  for (let i = 0; i < bin.length; i++) bytes[i] = bin.charCodeAt(i);
  return new TextDecoder().decode(bytes);
}

/**
 * Build an HTTP Basic-Auth header value: `Basic <base64(user:pass)>`.
 * Mirrors buildBasicAuth() in the TS source and BuildHeader() in the Go twin.
 *
 * @param {string} user
 * @param {string} pass
 * @returns {string}
 */
function buildBasicAuth(user, pass) {
  return 'Basic ' + b64encode(`${user}:${pass}`);
}

/**
 * Parse a `Basic <token>` header back into credentials, or null if the header
 * is malformed or the credentials have no colon separator.
 *
 * Logic mirrors ParseHeader() in the Go twin exactly: trim the header, require
 * a case-insensitive `basic ` prefix, trim the remaining token, base64-decode
 * it (a bad token throws and maps to null), then split on the FIRST colon so a
 * password containing colons round-trips.
 *
 * @param {string} header
 * @returns {BasicAuthCredentials | null}
 */
function parseBasicAuth(header) {
  const h = header.trim();
  // Case-insensitive "basic " prefix, mirroring Go's strings.EqualFold(h[:6], "basic ").
  if (h.length < 6 || h.slice(0, 6).toLowerCase() !== 'basic ') {
    return null;
  }
  const token = h.slice(6).trim();
  let creds;
  try {
    creds = b64decode(token);
  } catch {
    return null; // invalid base64
  }
  const idx = creds.indexOf(':');
  if (idx < 0) {
    return null; // no colon separator
  }
  return { user: creds.slice(0, idx), pass: creds.slice(idx + 1) };
}

// CommonJS export so the file is consumable from Node without a build step,
// while staying dependency-free and framework-agnostic. `BasicAuthCredentials`
// is a JSDoc @typedef above (a type-only contract), so it has no runtime value
// to export - mirroring how the slugify JS port treats its option typedefs.
module.exports = {
  buildBasicAuth,
  parseBasicAuth,
  b64encode,
  b64decode,
};

Also available in 13 other languages

Every CosmoDev tool ships its pure logic in TypeScript (web) and Go (CLI), with authored implementations in a dozen-plus languages — the same contract, ported. Compare all languages side by side →