Skip to content

Basic Auth Generator — Python 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 Python implementation — the same logic the interactive tool runs, in a shareable, citable form.

"""basic-auth-generator — HTTP Basic-Auth header encode/decode.

Language: Python (3.9+, standard library only)
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 raises (parse returns None 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 pip packages).

Python is the dependency-rich polyglot here — the standard library ships a
base64 codec and binascii validation, so unlike the Rust/PHP ports we use the
real RFC 4648 path rather than a hand-rolled codec. ``base64.b64decode`` with
``validate=True`` rejects invalid characters exactly like Go's
``base64.StdEncoding.DecodeString``.
"""

from __future__ import annotations

import base64
import binascii
from dataclasses import dataclass
from typing import Optional, Tuple

__all__ = ["Credentials", "build_basic_auth", "parse_basic_auth"]


@dataclass(frozen=True)
class Credentials:
    """A parsed username/password pair.

    Mirrors the Go twin's ``Credentials`` struct and the TS
    ``BasicAuthCredentials`` interface. Frozen so instances are hashable and
    immutable — the parsed value is a plain result, not a mutable bag.
    """

    user: str
    pass_: str
    """Password. Named ``pass_`` to avoid shadowing the Python keyword."""


def build_basic_auth(user: str, pass_: str) -> str:
    """Build an HTTP Basic-Auth header value: ``Basic <base64(user:pass)>``.

    Mirrors ``buildBasicAuth`` in the TS source and ``BuildHeader`` in the Go
    twin. ``encode`` returns the UTF-8 byte representation so multibyte
    credentials (e.g. ``café:päss``) encode correctly.
    """
    token = base64.b64encode(f"{user}:{pass_}".encode("utf-8")).decode("ascii")
    return f"Basic {token}"


def parse_basic_auth(header: str) -> Optional[Credentials]:
    """Parse a ``Basic <token>`` header back into credentials, or ``None`` 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 (rejecting invalid characters), then split on the FIRST
    colon so a password containing colons round-trips.
    """
    h = header.strip()
    prefix = "basic "
    # Case-insensitive prefix check, mirroring Go's strings.EqualFold(h[:6], "basic ").
    if len(h) < len(prefix) or h[: len(prefix)].lower() != prefix:
        return None

    token = h[len(prefix):].strip()
    try:
        decoded = base64.b64decode(token, validate=True).decode("utf-8")
    except (binascii.Error, ValueError, UnicodeDecodeError):
        return None

    # split with maxsplit=1 keeps any colons inside the password intact.
    if ":" not in decoded:
        return None
    user, pass_ = decoded.split(":", 1)
    return Credentials(user=user, pass_=pass_)

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 →