Basic Auth Generator — Kotlin 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 Kotlin implementation — the same logic the interactive tool runs, in a shareable, citable form.
// basic-auth-generator — HTTP Basic-Auth header encode/decode.
//
// Language: Kotlin (1.9, JVM, 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 (parseHeader 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: Kotlin stdlib + the JDK's java.util.Base64 (the RFC 4648
// standard codec, the direct equivalent of Go's encoding/base64).
//
// Two JDK quirks are compensated for below — java.util.Base64's basic decoder
// accepts unpadded input, and String construction from UTF-8 bytes silently
// replaces invalid sequences with U+FFFD — so both get the strict
// Go-equivalent behavior.
import java.nio.ByteBuffer
import java.nio.charset.CharacterCodingException
import java.nio.charset.CodingErrorAction
import java.nio.charset.StandardCharsets
import java.util.Base64
import java.util.Locale
/**
* A parsed username/password pair. Mirrors the Go twin's `Credentials` struct
* and the TS `BasicAuthCredentials` interface.
*/
data class Credentials(val user: String, val pass: String)
/**
* Build an HTTP Basic-Auth header value: `"Basic " + base64(user:pass)`.
* Mirrors `BuildHeader` in the Go twin and `buildBasicAuth` in the TS source.
* The UTF-8 byte representation is encoded, so multibyte credentials (e.g.
* `café:päss`) work.
*/
fun buildHeader(user: String, pass: String): String {
val raw = "$user:$pass".toByteArray(StandardCharsets.UTF_8)
return "Basic " + Base64.getEncoder().encodeToString(raw)
}
/**
* 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 (rejecting invalid characters), then split on the FIRST colon so a
* password containing colons round-trips.
*/
fun parseHeader(header: String): Credentials? {
val h = header.trim()
val prefix = "basic "
if (h.take(prefix.length).lowercase(Locale.ROOT) != prefix) return null
val token = h.substring(prefix.length).trim()
// The basic decoder ignores nothing and accepts missing padding, so strip
// whitespace and enforce the multiple-of-4 length ourselves — exactly
// like Go's StdEncoding.
val cleaned = token.replace(Regex("\\s+"), "")
if (cleaned.length % 4 != 0) return null
val decoded = try {
Base64.getDecoder().decode(cleaned)
} catch (e: IllegalArgumentException) {
return null
}
val text = decodeUtf8Strict(decoded) ?: return null
val colon = text.indexOf(':')
if (colon < 0) return null
return Credentials(text.substring(0, colon), text.substring(colon + 1))
}
/**
* Strict UTF-8 decode: `String(bytes, Charsets.UTF_8)` silently replaces
* malformed sequences with U+FFFD; the Go/Rust twins reject them, so this
* decoder reports them and maps the failure to null.
*/
private fun decodeUtf8Strict(bytes: ByteArray): String? =
try {
StandardCharsets.UTF_8.newDecoder()
.onMalformedInput(CodingErrorAction.REPORT)
.onUnmappableCharacter(CodingErrorAction.REPORT)
.decode(ByteBuffer.wrap(bytes))
.toString()
} catch (e: CharacterCodingException) {
null
}
// ---------- showcase-only demo (canonical suite lives in src/lib) ----------
fun main() {
val h = buildHeader("user", "pass")
check(h == "Basic dXNlcjpwYXNz") { "known vector mismatch: $h" }
println(h)
val roundTrips = listOf("alice" to "s3cr3t", "" to "x", "x" to "", "u" to "a:b:c")
for ((user, pass) in roundTrips) {
val creds = parseHeader(buildHeader(user, pass))
check(creds != null) { "round trip should parse for ($user, $pass)" }
check(creds.user == user) { "user mismatch for ($user, $pass)" }
check(creds.pass == pass) { "password mismatch for ($user, $pass)" } // colon-bearing pw intact
}
val malformed = listOf("Bearer xyz", "", "Basic !!!not-base64!!!", "Basic bm9jb2xvbg==")
for (bad in malformed) {
check(parseHeader(bad) == null) { "$bad should be rejected" }
}
println("all basic-auth-generator demo checks passed")
}
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 →