From 13449ad91cb26cb47661c1b080790392170385fd Mon Sep 17 00:00:00 2001 From: "Aeneas Rekkas (arekkas)" Date: Thu, 22 Jun 2017 17:12:08 +0200 Subject: [PATCH] internal: urlencode client id and secret in header As per https://tools.ietf.org/html/rfc6749#section-2.3.1 client IDs and secrets must be urlencoded in the authorization header. This patch addresses this by wrapping clientID and clientSecret with url.QueryEscape. A dedicated test for unsafe-url client IDs and secrets has been added as well. Closes #237 Change-Id: I1f277b52caef4932e14147be8fb1712203da51d0 Reviewed-on: https://go-review.googlesource.com/46473 Reviewed-by: JBD --- internal/token.go | 2 +- oauth2_test.go | 19 +++++++++++++++++++ 2 files changed, 20 insertions(+), 1 deletion(-) diff --git a/internal/token.go b/internal/token.go index 0487c81..53ec23c 100644 --- a/internal/token.go +++ b/internal/token.go @@ -188,7 +188,7 @@ func RetrieveToken(ctx context.Context, clientID, clientSecret, tokenURL string, } req.Header.Set("Content-Type", "application/x-www-form-urlencoded") if !bustedAuth { - req.SetBasicAuth(clientID, clientSecret) + req.SetBasicAuth(url.QueryEscape(clientID), url.QueryEscape(clientSecret)) } r, err := ctxhttp.Do(ctx, hc, req) if err != nil { diff --git a/oauth2_test.go b/oauth2_test.go index 584084b..09293ed 100644 --- a/oauth2_test.go +++ b/oauth2_test.go @@ -72,6 +72,25 @@ func TestAuthCodeURL_Optional(t *testing.T) { } } +func TestURLUnsafeClientConfig(t *testing.T) { + ts := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { + if got, want := r.Header.Get("Authorization"), "Basic Q0xJRU5UX0lEJTNGJTNGOkNMSUVOVF9TRUNSRVQlM0YlM0Y="; got != want { + t.Errorf("Authorization header = %q; want %q", got, want) + } + + w.Header().Set("Content-Type", "application/x-www-form-urlencoded") + w.Write([]byte("access_token=90d64460d14870c08c81352a05dedd3465940a7c&scope=user&token_type=bearer")) + })) + defer ts.Close() + conf := newConf(ts.URL) + conf.ClientID = "CLIENT_ID??" + conf.ClientSecret = "CLIENT_SECRET??" + _, err := conf.Exchange(context.Background(), "exchange-code") + if err != nil { + t.Error(err) + } +} + func TestExchangeRequest(t *testing.T) { ts := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { if r.URL.String() != "/token" {