diff --git a/README b/README
index 09ac664..cca57ae 100644
--- a/README
+++ b/README
@@ -54,13 +54,11 @@ gobyexample.com signups
 * https server
 * https client
 * buffered io
-* atomic ints
 * wait group
 * tcp proxy
 * http streaming server
 * http streaming client
 * http proxy
-* postgres
 * templating
 * web app
 * hipache port
@@ -82,5 +80,6 @@ gobyexample.com signups
 * compilation
 * time
 * string to/from numbers
+* http basic auth client
 * oauth for google domains
 * connection pool
diff --git a/src/xx-http-server-basic-auth.go b/src/xx-http-server-basic-auth.go
new file mode 100644
index 0000000..c8b43bb
--- /dev/null
+++ b/src/xx-http-server-basic-auth.go
@@ -0,0 +1,54 @@
+package main
+
+import (
+	"fmt"
+	"net/http"
+	"encoding/base64"
+	"strings"
+)
+
+type Authenticator func(string, string) bool
+
+func CheckAuth(r *http.Request, auth Authenticator) bool {
+	s := strings.SplitN(r.Header.Get("Authorization"), " ", 2)
+	if len(s) != 2 || s[0] != "Basic" {
+		return false
+	}
+	b, err := base64.StdEncoding.DecodeString(s[1])
+	if err != nil {
+		return false
+	}
+	pair := strings.SplitN(string(b), ":", 2)
+	if len(pair) != 2 {
+		return false
+	}
+	return auth(pair[0], pair[1])
+}
+
+func RequireAuth(w http.ResponseWriter, r *http.Request) {
+	w.Header().Set("WWW-Authenticate", `Basic realm="private"`)
+	w.WriteHeader(401)
+	w.Write([]byte("401 Unauthorized\n"))
+}
+
+func WithAuth(h http.HandlerFunc, a Authenticator) http.HandlerFunc {
+    return func(w http.ResponseWriter, r *http.Request) {
+    	if CheckAuth(r, a) {
+		  h(w, r)
+		} else {
+		  RequireAuth(w, r)
+		}
+	}
+}
+
+func handle(w http.ResponseWriter, r *http.Request) {
+    fmt.Fprintln(w, "Hello secret world!")
+}
+
+func main() {
+	authenticator := func(_, password string) bool {
+		return password == "supersecret"
+	}
+    http.HandleFunc("/", WithAuth(handle, authenticator))
+    http.ListenAndServe(":5000", nil)
+}