What does (*http.Request).BasicAuth return in Go, and when is its ok value false?
answer
- three results, not two
- the header is decoded, never verified
- scheme prefix, base64, then a split
- only the first colon separates
- false means unparseable, not wrong password
basics
~20 sBasicAuth on *http.Request returns username, password and ok. It reads the Authorization header, base64-decodes the credentials and splits them at the first colon. ok is false when the header is missing, is not the Basic scheme, or does not decode.
solid answer
~40 s`func (r *http.Request) BasicAuth() (username, password string, ok bool)` does the parsing for you: it takes the `Authorization` header value, checks for the `Basic` scheme prefix, base64-decodes the rest, and splits the decoded text at the **first** colon, so a password containing colons survives intact. `ok` is false in exactly four cases: no `Authorization` header, a different scheme such as Bearer, base64 that will not decode, and decoded text with no colon at all. The value of `ok` is a parsing verdict, not an authentication verdict — it tells you the caller sent something well formed, and nothing about whether the credentials are correct. You still have to compare the returned password against the expected secret yourself, and because base64 is encoding rather than encryption, Basic credentials are only safe over TLS.
code
go · 12 linesfunc parseBasic(r *http.Request) (user, pass string, ok bool) {
encoded, found := strings.CutPrefix(r.Header.Get("Authorization"), "Basic ")
if !found {
return "", "", false
}
raw, err := base64.StdEncoding.DecodeString(encoded)
if err != nil {
return "", "", false
}
user, pass, found = strings.Cut(string(raw), ":")
return user, pass, found
}go deeper
Be ready to name all three return values and say what makes the third one false. Say out loud that a successful parse is not a successful login.
Explain the parse itself: scheme prefix, base64 decode, split at the first colon, and why colons in a password survive. Then explain what has to happen after the parse.
Show the failure you would catch in review: code that gates on ok alone, or that compares the presented secret with ==, or that trusts an expected secret read from an unset environment variable.
Own the rule that credential parsing and credential verification are separate steps with separate owners, and that a helper which returns untrusted strings must never be the last line of defence in a service you are signing off.
## The method ```go func (r *http.Request) BasicAuth() (username, password string, ok bool) ``` It is a convenience parser on the request type in `net/http`. It reads only what the client sent; it contacts nothing, validates nothing, and stores nothing. ## What it does, step by step 1. It takes the `Authorization` request header value. If there is no such header the value is the empty string. 2. It checks that the value starts with the `Basic` scheme token followed by a space. Go's parser compares that prefix case-insensitively, because HTTP scheme tokens are case-insensitive. 3. It base64-decodes the remainder with standard encoding. 4. It splits the decoded text at the **first** colon. Everything before it is the username, everything after it is the password. Written out by hand the whole thing is about eight lines, which is why the helper exists — and why hand-rolled versions in review so often forget the scheme check or split on every colon. ## When ok is false - The request carried no `Authorization` header at all. - The header used a different scheme (`Bearer`, `Digest`, something custom). - The base64 payload is malformed. - The decoded payload contains no colon separator. In every one of those cases the two string results are empty. Nothing panics, and there is no error value to inspect — the boolean is the whole signal. ## The trap: ok is not authentication A surprising amount of broken middleware reads like this: ```go if _, _, ok := r.BasicAuth(); !ok { // reject } // ...and then serves the resource ``` That code lets anyone through who sends any syntactically valid Basic header. `ok == true` means the caller sent a well-formed, attacker-controlled pair of strings. Treat both strings as untrusted input: they came off the wire, they can be any length, and they can contain any bytes that survive base64. The check that actually matters is the comparison of the presented secret against the expected one, and that comparison should not be a plain `==` on secret material — a comparison that returns early on the first differing byte tells the caller how much of the secret they guessed. `crypto/subtle` exists for that. ## Colons and empty passwords Because only the first colon splits, `admin:s3:cret` yields username `admin` and password `s3:cret`. A trailing colon (`admin:`) yields an empty password with `ok` true — a password of zero length is well formed, so if your expected secret is also empty (an unset environment variable read with `os.Getenv` returns the empty string) the comparison succeeds and the endpoint is wide open. Validate the configured secret at startup instead of at request time. ## The response side When the credential is missing or wrong, the caller is *unauthenticated* and the status is 401. When the credential is good but the identity is not allowed to touch this resource, the caller is *authenticated but unauthorised* and the status is 403. Deciding which one you are in is exactly the distinction this parse makes possible. ## The client side The mirror image is `req.SetBasicAuth(username, password)`, which base64-encodes the pair and sets the `Authorization` header on an outgoing request. It does not encrypt anything and it does not force TLS; if you send it over plaintext HTTP the credentials are on the wire in recoverable form. ## What to say in an interview Three returns; the third is a parse verdict; the parse is prefix check, base64 decode, split at the first colon; the strings are untrusted; the real work is the comparison that follows, and that comparison should be constant-time.
- If ok comes back true, what have you actually established about the caller?Only that they sent an Authorization header using the Basic scheme whose payload decoded and contained a colon. The username and password are attacker-controlled strings of any content. Nothing about identity is established until you compare the presented secret against the expected one, and that comparison should be constant-time.
- The decoded credentials are admin:s3:cret. What does BasicAuth return?Username `admin`, password `s3:cret`, ok true. The split happens at the first colon only, so colons inside a password are preserved. A trailing colon gives an empty password with ok still true — which is why an unset expected secret is dangerous, since it would match.
- How do you attach Basic credentials to an outgoing request in Go?`req.SetBasicAuth(user, pass)` on the `*http.Request` before you send it. It base64-encodes `user:pass` and sets the `Authorization` header. It provides no confidentiality on its own — the credentials are recoverable from the wire unless the request goes over TLS.
saying these in an interview costs you the question
- Treats ok true as proof the credentials are valid
- Thinks base64 in the Authorization header protects the password
- Splits the decoded credentials on every colon, corrupting passwords
- Hand-parses the header and skips the scheme prefix check
- Assumes a missing Authorization header makes BasicAuth panic
- Compares the presented password against an unset, empty expected secret