yudai/gotty · warning
authorization failed
Error message
authorization failed
What it means
GoTTY's wrapBasicAuth middleware in server/middleware.go:44 returns HTTP 401 'authorization failed' when the Base64-decoded Authorization payload does not exactly equal the credential string the server was started with (-credential user:pass). The comparison `credential != string(payload)` is a plain string match, so any mismatch in username, password, or the 'user:pass' combined format rejects the request and sets the WWW-Authenticate: Basic realm="GoTTY" challenge.
Source
Thrown at server/middleware.go:44
func (server *Server) wrapBasicAuth(handler http.Handler, credential string) http.Handler {
return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
token := strings.SplitN(r.Header.Get("Authorization"), " ", 2)
if len(token) != 2 || strings.ToLower(token[0]) != "basic" {
w.Header().Set("WWW-Authenticate", `Basic realm="GoTTY"`)
http.Error(w, "Bad Request", http.StatusUnauthorized)
return
}
payload, err := base64.StdEncoding.DecodeString(token[1])
if err != nil {
http.Error(w, "Internal Server Error", http.StatusInternalServerError)
return
}
if credential != string(payload) {
w.Header().Set("WWW-Authenticate", `Basic realm="GoTTY"`)
http.Error(w, "authorization failed", http.StatusUnauthorized)
return
}
log.Printf("Basic Authentication Succeeded: %s", r.RemoteAddr)
handler.ServeHTTP(w, r)
})
}
View on GitHub (pinned to a080c85cbc)
Solutions
- Re-encode the exact expected value: printf '%s' 'user:pass' | base64 and send that in 'Authorization: Basic <token>' (or use curl -u user:pass)
- Verify the credential the server was started with (the -credential flag / config) matches what the client is sending, including case and any special characters
- Confirm the Authorization header survives intermediaries; test directly against the GoTTY port bypassing proxies
- Inspect for hidden whitespace/newlines in the encoded token (base64 with line wrapping) and strip them
Example fix
// before
req.Header.Set("Authorization", "Basic "+base64.StdEncoding.EncodeToString([]byte("wrongpass")))
// 401 authorization failed
// after
cred := "user:pass" // must match server's -credential exactly
req.SetBasicAuth("user", "pass") // sends Basic base64("user:pass") Defensive patterns
Strategy: validation
Validate before calling
expected := "user:pass" // must match server -credential exactly
if base64.StdEncoding.EncodeToString([]byte(expected)) != token {
log.Printf("credential mismatch: re-encode from the server's configured credential")
} Try / catch
resp, err := client.Do(req)
if err == nil && resp.StatusCode == http.StatusUnauthorized {
// 401 'authorization failed': check credential vs server's -credential,
// refresh credentials, then retry once with corrected values
} Prevention
- Keep server -credential and client credentials in one shared source (env var/config file) to avoid drift
- Use a client library helper (SetBasicAuth, curl -u) rather than hand-encoding
- After changing the server's credential, update and re-test all clients
- Verify against the server directly before blaming proxies; check for header-stripping middleware on reverse proxies
When it happens
Trigger: A request sends a validly Base64-encoded Basic header whose decoded value is not exactly the configured credential: wrong password, wrong username, missing the 'username:password' colon format (sending just 'password'), or the server was started with a different -credential value than the client uses.
Common situations: Stale credentials in client config or environment variables after a server restart with a new -credential flag, URL special characters in a password that shell-encode differently than expected, a reverse proxy stripping or rewriting Authorization headers, clients encoding 'user:pass ' with a trailing space/newline, or team members sharing an encoded token generated from different credentials.
Related errors
AI-assisted analysis of yudai/gotty@a080c85cbc (2026-09-02).
Data as JSON: /api/errors/c2f511d82308a05a.
Report an issue: GitHub.