From 1c0f83ffd5d9160d18c2cafdf8625ce4b0d2a5b1 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Mislav=20Marohni=C4=87?= Date: Thu, 27 Aug 2020 14:10:16 +0200 Subject: [PATCH] Handle "unauthorized_client" HTTP 400 error when doing Device Flow The "unauthorized_client" error means that OAuth Device Flow is implemented, but either isn't enabled on this GHES instance, or that it isn't enabled for this particular OAuth app. In these cases we fall back to old OAuth app authorization flow. --- auth/oauth.go | 29 ++++++++++++++++++----------- 1 file changed, 18 insertions(+), 11 deletions(-) diff --git a/auth/oauth.go b/auth/oauth.go index adc5231ef..3a933811c 100644 --- a/auth/oauth.go +++ b/auth/oauth.go @@ -57,21 +57,28 @@ func (oa *OAuthFlow) ObtainAccessToken() (accessToken string, err error) { } defer resp.Body.Close() - if resp.StatusCode == 401 || resp.StatusCode == 403 || resp.StatusCode == 404 { - // OAuth Device Flow is not available; continue with OAuth browser flow with a - // local server endpoint as callback target - return oa.localServerFlow() - } else if resp.StatusCode != 200 { - return "", fmt.Errorf("error: HTTP %d (%s)", resp.StatusCode, initURL) - } - + var values url.Values bb, err := ioutil.ReadAll(resp.Body) if err != nil { return } - values, err := url.ParseQuery(string(bb)) - if err != nil { - return + if resp.StatusCode == 200 || strings.HasPrefix(resp.Header.Get("Content-Type"), "application/x-www-form-urlencoded") { + values, err = url.ParseQuery(string(bb)) + if err != nil { + return + } + } + + if resp.StatusCode == 401 || resp.StatusCode == 403 || resp.StatusCode == 404 || + (resp.StatusCode == 400 && values != nil && values.Get("error") == "unauthorized_client") { + // OAuth Device Flow is not available; continue with OAuth browser flow with a + // local server endpoint as callback target + return oa.localServerFlow() + } else if resp.StatusCode != 200 { + if values != nil && values.Get("error_description") != "" { + return "", fmt.Errorf("HTTP %d: %s (%s)", resp.StatusCode, values.Get("error_description"), initURL) + } + return "", fmt.Errorf("error: HTTP %d (%s)", resp.StatusCode, initURL) } timeNow := oa.TimeNow