diff --git a/cmd/dex/serve.go b/cmd/dex/serve.go
index 932f6c5374403357f7115f39c411b4e9f9d57fa0..be27f12b65a44d05ddb3c24a2c357f6a61dca221 100644
--- a/cmd/dex/serve.go
+++ b/cmd/dex/serve.go
@@ -92,6 +92,8 @@ func serve(cmd *cobra.Command, args []string) error {
 		Issuer:     c.Issuer,
 		Connectors: connectors,
 		Storage:    s,
+
+		SupportedResponseTypes: c.OAuth2.ResponseTypes,
 	}
 
 	serv, err := server.New(serverConfig)
diff --git a/server/handlers.go b/server/handlers.go
index 7c9bba58fc7d658d0f6e552780477057f5995c84..3aa0b368bcdb8850ce092da45b932b9f227b4439 100644
--- a/server/handlers.go
+++ b/server/handlers.go
@@ -8,6 +8,7 @@ import (
 	"net/http"
 	"net/url"
 	"path"
+	"sort"
 	"strconv"
 	"strings"
 	"time"
@@ -72,32 +73,37 @@ type discovery struct {
 	Claims        []string `json:"claims_supported"`
 }
 
-func (s *Server) handleDiscovery(w http.ResponseWriter, r *http.Request) {
-	// TODO(ericchiang): Cache this
+func (s *Server) discoveryHandler() (http.HandlerFunc, error) {
 	d := discovery{
-		Issuer:        s.issuerURL.String(),
-		Auth:          s.absURL("/auth"),
-		Token:         s.absURL("/token"),
-		Keys:          s.absURL("/keys"),
-		ResponseTypes: []string{"code"},
-		Subjects:      []string{"public"},
-		IDTokenAlgs:   []string{string(jose.RS256)},
-		Scopes:        []string{"openid", "email", "profile", "offline_access"},
-		AuthMethods:   []string{"client_secret_basic"},
+		Issuer:      s.issuerURL.String(),
+		Auth:        s.absURL("/auth"),
+		Token:       s.absURL("/token"),
+		Keys:        s.absURL("/keys"),
+		Subjects:    []string{"public"},
+		IDTokenAlgs: []string{string(jose.RS256)},
+		Scopes:      []string{"openid", "email", "profile", "offline_access"},
+		AuthMethods: []string{"client_secret_basic"},
 		Claims: []string{
 			"aud", "email", "email_verified", "exp",
 			"iat", "iss", "locale", "name", "sub",
 		},
 	}
+
+	for responseType := range s.supportedResponseTypes {
+		d.ResponseTypes = append(d.ResponseTypes, responseType)
+	}
+	sort.Strings(d.ResponseTypes)
+
 	data, err := json.MarshalIndent(d, "", "  ")
 	if err != nil {
-		log.Printf("failed to marshal discovery data: %v", err)
-		http.Error(w, "Internal server error", http.StatusInternalServerError)
-		return
+		return nil, fmt.Errorf("failed to marshal discovery data: %v", err)
 	}
-	w.Header().Set("Content-Type", "application/json")
-	w.Header().Set("Content-Length", strconv.Itoa(len(data)))
-	w.Write(data)
+
+	return func(w http.ResponseWriter, r *http.Request) {
+		w.Header().Set("Content-Type", "application/json")
+		w.Header().Set("Content-Length", strconv.Itoa(len(data)))
+		w.Write(data)
+	}, nil
 }
 
 // handleAuthorization handles the OAuth2 auth endpoint.
diff --git a/server/server.go b/server/server.go
index bb488f54ef7f2f2934b5cbaff287cd81c427ccaf..ef2697dbe2d781a27d6200bb75d0aecf52f9e0a2 100644
--- a/server/server.go
+++ b/server/server.go
@@ -136,8 +136,13 @@ func newServer(c Config, rotationStrategy rotationStrategy) (*Server, error) {
 	}
 	r.NotFoundHandler = http.HandlerFunc(s.notFound)
 
+	discoveryHandler, err := s.discoveryHandler()
+	if err != nil {
+		return nil, err
+	}
+	handleFunc("/.well-known/openid-configuration", discoveryHandler)
+
 	// TODO(ericchiang): rate limit certain paths based on IP.
-	handleFunc("/.well-known/openid-configuration", s.handleDiscovery)
 	handleFunc("/token", s.handleToken)
 	handleFunc("/keys", s.handlePublicKeys)
 	handleFunc("/auth", s.handleAuthorization)