@@ -30,6 +30,17 @@ type ErrorResponse struct {
3030 ErrorDescription string `json:"error_description"`
3131}
3232
33+ // parseOAuthError attempts to unmarshal an OAuth error response from raw JSON.
34+ // Returns the parsed response and true if successful, or a zero value and false
35+ // if the body is not a valid OAuth error (missing "error" field).
36+ func parseOAuthError (body []byte ) (ErrorResponse , bool ) {
37+ var errResp ErrorResponse
38+ if err := json .Unmarshal (body , & errResp ); err != nil || errResp .Error == "" {
39+ return ErrorResponse {}, false
40+ }
41+ return errResp , true
42+ }
43+
3344// readResponseBody reads the response body with a size limit to guard against oversized responses.
3445func readResponseBody (resp * http.Response ) ([]byte , error ) {
3546 body , err := io .ReadAll (io .LimitReader (resp .Body , maxResponseBodySize ))
@@ -42,10 +53,10 @@ func readResponseBody(resp *http.Response) ([]byte, error) {
4253// formatHTTPError attempts to parse an OAuth error response from body,
4354// falling back to a generic status+body error message.
4455func formatHTTPError (body []byte , statusCode int ) error {
45- var errResp ErrorResponse
46- if json . Unmarshal ( body , & errResp ) == nil && errResp . Error != "" {
47- if errResp . ErrorDescription != "" {
48- return fmt .Errorf ("%s: %s" , errResp .Error , errResp . ErrorDescription )
56+ if errResp , ok := parseOAuthError ( body ); ok {
57+ desc := strings . TrimSpace ( errResp . ErrorDescription )
58+ if desc != "" {
59+ return fmt .Errorf ("%s: %s" , errResp .Error , desc )
4960 }
5061 return fmt .Errorf ("%s" , errResp .Error )
5162 }
@@ -83,18 +94,13 @@ func doTokenExchange(
8394 }
8495
8596 if resp .StatusCode != http .StatusOK {
86- var errResp ErrorResponse
87- if jsonErr := json .Unmarshal (body , & errResp ); jsonErr == nil && errResp .Error != "" {
97+ if errResp , ok := parseOAuthError (body ); ok {
8898 if errHook != nil {
8999 if hookErr := errHook (errResp , body ); hookErr != nil {
90100 return nil , hookErr
91101 }
92102 }
93- desc := strings .TrimSpace (errResp .ErrorDescription )
94- if desc == "" {
95- return nil , fmt .Errorf ("%s" , errResp .Error )
96- }
97- return nil , fmt .Errorf ("%s: %s" , errResp .Error , desc )
103+ return nil , formatHTTPError (body , resp .StatusCode )
98104 }
99105 return nil , fmt .Errorf (
100106 "token exchange failed with status %d: %s" ,
0 commit comments