diff --git a/httpbin/handlers.go b/httpbin/handlers.go
index 29ed07d4067783d19e1c39c99dfbcb897157fbf1..64bed3f8cf29e1e06099726c28c4fe4ddf197f8b 100644
--- a/httpbin/handlers.go
+++ b/httpbin/handlers.go
@@ -11,6 +11,8 @@ import (
 	"strconv"
 	"strings"
 	"time"
+
+	"github.com/mccutchen/go-httpbin/httpbin/digest"
 )
 
 var acceptedMediaTypes = []string{
@@ -841,3 +843,47 @@ func doImage(w http.ResponseWriter, kind string) {
 func (h *HTTPBin) XML(w http.ResponseWriter, r *http.Request) {
 	writeResponse(w, http.StatusOK, "application/xml", MustAsset("sample.xml"))
 }
+
+// DigestAuth blah
+//
+// /digest-auth/<qop>/<user>/<passwd>
+// /digest-auth/<qop>/<user>/<passwd>/<algorithm>
+func (h *HTTPBin) DigestAuth(w http.ResponseWriter, r *http.Request) {
+	parts := strings.Split(r.URL.Path, "/")
+	count := len(parts)
+
+	if count != 5 && count != 6 {
+		http.Error(w, "Not Found", http.StatusNotFound)
+		return
+	}
+
+	qop := strings.ToLower(parts[2])
+	user := parts[3]
+	password := parts[4]
+
+	algorithm := "MD5"
+	if count == 6 {
+		algorithm = strings.ToUpper(parts[5])
+	}
+
+	if qop != "auth" {
+		http.Error(w, "Invalid QOP directive", http.StatusBadRequest)
+		return
+	}
+	if algorithm != "MD5" && algorithm != "SHA-256" {
+		http.Error(w, "Invalid algorithm", http.StatusBadRequest)
+		return
+	}
+
+	if !digest.Check(r, user, password) {
+		w.Header().Set("WWW-Authenticate", digest.Challenge("go-httpbin", algorithm))
+		w.WriteHeader(http.StatusUnauthorized)
+		return
+	}
+
+	resp, _ := json.Marshal(&authResponse{
+		Authorized: true,
+		User:       user,
+	})
+	writeJSON(w, resp, http.StatusOK)
+}
diff --git a/httpbin/helpers.go b/httpbin/helpers.go
index 682996e2de720cd7e0e950b988855a3072e39e95..e1d94fd7c398d432203f7f5d9e5fd4a4a6c15437 100644
--- a/httpbin/helpers.go
+++ b/httpbin/helpers.go
@@ -77,6 +77,7 @@ func parseBody(w http.ResponseWriter, r *http.Request, resp *bodyResponse, maxMe
 
 	// Restrict size of request body
 	r.Body = http.MaxBytesReader(w, r.Body, maxMemory)
+	defer r.Body.Close()
 
 	ct := r.Header.Get("Content-Type")
 	switch {
diff --git a/httpbin/httpbin.go b/httpbin/httpbin.go
index 69d38cdb484508697ac9d8683ace7ece816f66e0..1c2a462752e17d82b8c103426a581077aff2c774 100644
--- a/httpbin/httpbin.go
+++ b/httpbin/httpbin.go
@@ -114,6 +114,7 @@ func (h *HTTPBin) Handler() http.Handler {
 
 	mux.HandleFunc("/basic-auth/", h.BasicAuth)
 	mux.HandleFunc("/hidden-basic-auth/", h.HiddenBasicAuth)
+	mux.HandleFunc("/digest-auth/", h.DigestAuth)
 
 	mux.HandleFunc("/deflate", h.Deflate)
 	mux.HandleFunc("/gzip", h.Gzip)
@@ -140,9 +141,6 @@ func (h *HTTPBin) Handler() http.Handler {
 	mux.HandleFunc("/image/", h.Image)
 	mux.HandleFunc("/xml", h.XML)
 
-	// Not implemented
-	mux.HandleFunc("/digest-auth/", notImplementedHandler)
-
 	// Make sure our ServeMux doesn't "helpfully" redirect these invalid
 	// endpoints by adding a trailing slash. See the ServeMux docs for more
 	// info: https://golang.org/pkg/net/http/#ServeMux