Basic Auth Generator — C++ 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 C++ implementation — the same logic the interactive tool runs, in a shareable, citable form.
// basic-auth-generator — HTTP Basic-Auth header encode/decode.
//
// Language: C++ (C++17, 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 throws (parse_header returns std::nullopt
// on malformed input).
// - Functionally equivalent to the TS reference + Go twin: same inputs ->
// same outputs, same reject behavior on malformed headers.
// - Self-contained: std only (noBoost or other codec dependencies).
//
// Unicode note: C++ has no stdlib base64 codec, so the full RFC 4648 §4
// standard encoder/decoder is implemented inline (like the Rust port).
// std::string is a byte string, so multibyte UTF-8 credentials (e.g.
// "café:päss") encode correctly; C++17 ships no UTF-8 validator, so decoded
// bytes pass through unchanged — byte-for-byte compatible with the other
// ports for every valid input.
#include <cctype>
#include <cstddef>
#include <optional>
#include <string>
// RFC 4648 §4 standard base64 alphabet.
static const char *const B64_ALPHABET =
"ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
// Reverse lookup: value of one base64 digit, or -1 if not in the alphabet.
static int b64_value(char c) {
unsigned char u = static_cast<unsigned char>(c);
if (u >= 'A' && u <= 'Z') return u - 'A';
if (u >= 'a' && u <= 'z') return u - 'a' + 26;
if (u >= '0' && u <= '9') return u - '0' + 52;
if (c == '+') return 62;
if (c == '/') return 63;
return -1;
}
// Encode arbitrary bytes into standard base64 (with '=' padding), matching
// Go's base64.StdEncoding.EncodeToString. Processes input in 3-byte groups,
// emitting 4 characters per group; a trailing 1- or 2-byte group emits 2 or 3
// characters plus '=' padding.
static std::string b64_encode(const std::string &bytes) {
std::string out;
out.reserve((bytes.size() + 2) / 3 * 4);
for (std::size_t i = 0; i < bytes.size(); i += 3) {
unsigned b0 = static_cast<unsigned char>(bytes[i]);
unsigned b1 = (i + 1 < bytes.size()) ? static_cast<unsigned char>(bytes[i + 1]) : 0u;
unsigned b2 = (i + 2 < bytes.size()) ? static_cast<unsigned char>(bytes[i + 2]) : 0u;
unsigned n = (b0 << 16) | (b1 << 8) | b2;
out.push_back(B64_ALPHABET[(n >> 18) & 0x3Fu]);
out.push_back(B64_ALPHABET[(n >> 12) & 0x3Fu]);
out.push_back((i + 1 < bytes.size()) ? B64_ALPHABET[(n >> 6) & 0x3Fu] : '=');
out.push_back((i + 2 < bytes.size()) ? B64_ALPHABET[n & 0x3Fu] : '=');
}
return out;
}
// Decode a standard base64 string into bytes. Whitespace inside the token is
// ignored; the cleaned length must be a multiple of 4; any character outside
// the alphabet (other than '=' padding) is rejected. Mirrors Go's
// base64.StdEncoding.DecodeString (error -> std::nullopt).
static std::optional<std::string> b64_decode(const std::string &input) {
std::string cleaned;
cleaned.reserve(input.size());
for (char c : input) {
if (!std::isspace(static_cast<unsigned char>(c))) cleaned.push_back(c);
}
if (cleaned.size() % 4 != 0) return std::nullopt;
std::string out;
out.reserve(cleaned.size() / 4 * 3);
for (std::size_t i = 0; i < cleaned.size(); i += 4) {
unsigned idx[4] = {0u, 0u, 0u, 0u};
int pads = 0;
for (int j = 0; j < 4; ++j) {
char c = cleaned[i + static_cast<std::size_t>(j)];
if (c == '=') {
++pads;
} else {
int v = b64_value(c);
if (v < 0) return std::nullopt; // invalid character
idx[j] = static_cast<unsigned>(v);
}
}
unsigned n = (idx[0] << 18) | (idx[1] << 12) | (idx[2] << 6) | idx[3];
out.push_back(static_cast<char>((n >> 16) & 0xFFu));
if (pads < 2) out.push_back(static_cast<char>((n >> 8) & 0xFFu));
if (pads < 1) out.push_back(static_cast<char>(n & 0xFFu));
}
return out;
}
// Credentials hold a parsed username/password pair. Mirrors the Go twin's
// Credentials struct and the TS BasicAuthCredentials interface.
struct Credentials {
std::string user;
std::string pass;
};
// Build an HTTP Basic-Auth header value: "Basic " + base64(user:pass).
// Mirrors BuildHeader in the Go twin and buildBasicAuth in the TS source.
std::string build_header(const std::string &user, const std::string &pass) {
return "Basic " + b64_encode(user + ":" + pass);
}
// Trim ASCII whitespace from both ends (std::string has no trim in C++17).
static std::string trimmed(const std::string &s) {
std::size_t b = 0;
std::size_t e = s.size();
while (b < e && std::isspace(static_cast<unsigned char>(s[b]))) ++b;
while (e > b && std::isspace(static_cast<unsigned char>(s[e - 1]))) --e;
return s.substr(b, e - b);
}
// Parse a "Basic <token>" header back into credentials, or std::nullopt 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.
std::optional<Credentials> parse_header(const std::string &header) {
const std::string h = trimmed(header);
static const std::string prefix = "basic ";
if (h.size() < prefix.size()) return std::nullopt;
for (std::size_t i = 0; i < prefix.size(); ++i) {
if (std::tolower(static_cast<unsigned char>(h[i])) != prefix[i]) return std::nullopt;
}
const std::string token = trimmed(h.substr(prefix.size()));
const std::optional<std::string> decoded = b64_decode(token);
if (!decoded.has_value()) return std::nullopt;
const std::size_t colon = decoded->find(':');
if (colon == std::string::npos) return std::nullopt;
return Credentials{decoded->substr(0, colon), decoded->substr(colon + 1)};
}
// ---------- showcase-only demo (canonical suite lives in src/lib) ----------
// Compile with -DBASIC_AUTH_DEMO to run the same vectors as the Rust port.
#ifdef BASIC_AUTH_DEMO
#include <cassert>
#include <iostream>
int main() {
std::string h = build_header("user", "pass");
assert(h == "Basic dXNlcjpwYXNz");
std::cout << h << '\n';
const std::pair<std::string, std::string> round_trips[] = {
{"alice", "s3cr3t"}, {"", "x"}, {"x", ""}, {"u", "a:b:c"},
};
for (const auto &[user, pass] : round_trips) {
auto creds = parse_header(build_header(user, pass));
assert(creds.has_value());
assert(creds->user == user);
assert(creds->pass == pass); // colon-bearing password intact
}
const std::string malformed[] = {
"Bearer xyz", "", "Basic !!!not-base64!!!", "Basic bm9jb2xvbg==", // "nocolon"
};
for (const std::string &bad : malformed) {
assert(!parse_header(bad).has_value());
}
std::cout << "all basic-auth-generator demo checks passed\n";
return 0;
}
#endif
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 →