clientcredentials: allow override of grant_type

Password-based authentication to the [Keycloak](https://www.keycloak.org/) API requires `grant_type` to be `password`. It would be very helpful if `golang.org/x/oauth2` could be used for this, and all's that missing is the ability to override `grant_type`.

Fixes #283

Change-Id: I439dccb3e57042571ad92f115442ae1b7d59d4e0
GitHub-Last-Rev: 0e6f85e31efd7122721d75947178100eac62df0e
GitHub-Pull-Request: golang/oauth2#363
Reviewed-on: https://go-review.googlesource.com/c/158517
Run-TryBot: Brad Fitzpatrick <bradfitz@golang.org>
TryBot-Result: Gobot Gobot <gobot@golang.org>
Reviewed-by: Brad Fitzpatrick <bradfitz@golang.org>
diff --git a/clientcredentials/clientcredentials.go b/clientcredentials/clientcredentials.go
index 3c816bb..0812964 100644
--- a/clientcredentials/clientcredentials.go
+++ b/clientcredentials/clientcredentials.go
@@ -90,7 +90,9 @@
 		v.Set("scope", strings.Join(c.conf.Scopes, " "))
 	}
 	for k, p := range c.conf.EndpointParams {
-		if _, ok := v[k]; ok {
+		// Allow grant_type to be overridden to allow interoperability with
+		// non-compliant implementations.
+		if _, ok := v[k]; ok && k != "grant_type" {
 			return nil, fmt.Errorf("oauth2: cannot overwrite parameter %q", k)
 		}
 		v[k] = p
diff --git a/clientcredentials/clientcredentials_test.go b/clientcredentials/clientcredentials_test.go
index 108520c..35cbd54 100644
--- a/clientcredentials/clientcredentials_test.go
+++ b/clientcredentials/clientcredentials_test.go
@@ -31,6 +31,43 @@
 	return t.rt(req)
 }
 
+func TestTokenSourceGrantTypeOverride(t *testing.T) {
+	wantGrantType := "password"
+	var gotGrantType string
+	ts := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
+		body, err := ioutil.ReadAll(r.Body)
+		if err != nil {
+			t.Errorf("ioutil.ReadAll(r.Body) == %v, %v, want _, <nil>", body, err)
+		}
+		if err := r.Body.Close(); err != nil {
+			t.Errorf("r.Body.Close() == %v, want <nil>", err)
+		}
+		values, err := url.ParseQuery(string(body))
+		if err != nil {
+			t.Errorf("url.ParseQuery(%q) == %v, %v, want _, <nil>", body, values, err)
+		}
+		gotGrantType = values.Get("grant_type")
+		w.Header().Set("Content-Type", "application/x-www-form-urlencoded")
+		w.Write([]byte("access_token=90d64460d14870c08c81352a05dedd3465940a7c&token_type=bearer"))
+	}))
+	config := &Config{
+		ClientID:     "CLIENT_ID",
+		ClientSecret: "CLIENT_SECRET",
+		Scopes:       []string{"scope"},
+		TokenURL:     ts.URL + "/token",
+		EndpointParams: url.Values{
+			"grant_type": {wantGrantType},
+		},
+	}
+	token, err := config.TokenSource(context.Background()).Token()
+	if err != nil {
+		t.Errorf("config.TokenSource(_).Token() == %v, %v, want !<nil>, <nil>", token, err)
+	}
+	if gotGrantType != wantGrantType {
+		t.Errorf("grant_type == %q, want %q", gotGrantType, wantGrantType)
+	}
+}
+
 func TestTokenRequest(t *testing.T) {
 	ts := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
 		if r.URL.String() != "/token" {