@@ -44,11 +44,13 @@ def _handle_error_response(response_data):
4444 """Translates an error response into an exception.
4545
4646 Args:
47- response_data (Mapping): The decoded response data.
47+ response_data (Mapping | str ): The decoded response data.
4848
4949 Raises:
5050 google.auth.exceptions.RefreshError: The errors contained in response_data.
5151 """
52+ if isinstance (response_data , six .string_types ):
53+ raise exceptions .RefreshError (response_data )
5254 try :
5355 error_details = "{}: {}" .format (
5456 response_data ["error" ], response_data .get ("error_description" )
@@ -79,7 +81,13 @@ def _parse_expiry(response_data):
7981
8082
8183def _token_endpoint_request_no_throw (
82- request , token_uri , body , access_token = None , use_json = False
84+ request ,
85+ token_uri ,
86+ body ,
87+ access_token = None ,
88+ use_json = False ,
89+ expected_status_code = http_client .OK ,
90+ ** kwargs
8391):
8492 """Makes a request to the OAuth 2.0 authorization server's token endpoint.
8593 This function doesn't throw on response errors.
@@ -93,6 +101,16 @@ def _token_endpoint_request_no_throw(
93101 access_token (Optional(str)): The access token needed to make the request.
94102 use_json (Optional(bool)): Use urlencoded format or json format for the
95103 content type. The default value is False.
104+ expected_status_code (Optional(int)): The expected the status code of
105+ the token response. The default value is 200. We may expect other
106+ status code like 201 for GDCH credentials.
107+ kwargs: Additional arguments passed on to the request method. The
108+ kwargs will be passed to `requests.request` method, see:
109+ https://docs.python-requests.org/en/latest/api/#requests.request.
110+ For example, you can use `cert=("cert_pem_path", "key_pem_path")`
111+ to set up client side SSL certificate, and use
112+ `verify="ca_bundle_path"` to set up the CA certificates for sever
113+ side SSL certificate verification.
96114
97115 Returns:
98116 Tuple(bool, Mapping[str, str]): A boolean indicating if the request is
@@ -112,32 +130,46 @@ def _token_endpoint_request_no_throw(
112130 # retry to fetch token for maximum of two times if any internal failure
113131 # occurs.
114132 while True :
115- response = request (method = "POST" , url = token_uri , headers = headers , body = body )
133+ response = request (
134+ method = "POST" , url = token_uri , headers = headers , body = body , ** kwargs
135+ )
116136 response_body = (
117137 response .data .decode ("utf-8" )
118138 if hasattr (response .data , "decode" )
119139 else response .data
120140 )
121- response_data = json .loads (response_body )
122141
123- if response .status == http_client .OK :
142+ if response .status == expected_status_code :
143+ # response_body should be a JSON
144+ response_data = json .loads (response_body )
124145 break
125146 else :
126- error_desc = response_data .get ("error_description" ) or ""
127- error_code = response_data .get ("error" ) or ""
128- if (
129- any (e == "internal_failure" for e in (error_code , error_desc ))
130- and retry < 1
131- ):
132- retry += 1
133- continue
134- return response .status == http_client .OK , response_data
135-
136- return response .status == http_client .OK , response_data
147+ # For a failed response, response_body could be a string
148+ try :
149+ response_data = json .loads (response_body )
150+ error_desc = response_data .get ("error_description" ) or ""
151+ error_code = response_data .get ("error" ) or ""
152+ if (
153+ any (e == "internal_failure" for e in (error_code , error_desc ))
154+ and retry < 1
155+ ):
156+ retry += 1
157+ continue
158+ except ValueError :
159+ response_data = response_body
160+ return False , response_data
161+
162+ return response .status == expected_status_code , response_data
137163
138164
139165def _token_endpoint_request (
140- request , token_uri , body , access_token = None , use_json = False
166+ request ,
167+ token_uri ,
168+ body ,
169+ access_token = None ,
170+ use_json = False ,
171+ expected_status_code = http_client .OK ,
172+ ** kwargs
141173):
142174 """Makes a request to the OAuth 2.0 authorization server's token endpoint.
143175
@@ -150,6 +182,16 @@ def _token_endpoint_request(
150182 access_token (Optional(str)): The access token needed to make the request.
151183 use_json (Optional(bool)): Use urlencoded format or json format for the
152184 content type. The default value is False.
185+ expected_status_code (Optional(int)): The expected the status code of
186+ the token response. The default value is 200. We may expect other
187+ status code like 201 for GDCH credentials.
188+ kwargs: Additional arguments passed on to the request method. The
189+ kwargs will be passed to `requests.request` method, see:
190+ https://docs.python-requests.org/en/latest/api/#requests.request.
191+ For example, you can use `cert=("cert_pem_path", "key_pem_path")`
192+ to set up client side SSL certificate, and use
193+ `verify="ca_bundle_path"` to set up the CA certificates for sever
194+ side SSL certificate verification.
153195
154196 Returns:
155197 Mapping[str, str]: The JSON-decoded response data.
@@ -159,7 +201,13 @@ def _token_endpoint_request(
159201 an error.
160202 """
161203 response_status_ok , response_data = _token_endpoint_request_no_throw (
162- request , token_uri , body , access_token = access_token , use_json = use_json
204+ request ,
205+ token_uri ,
206+ body ,
207+ access_token = access_token ,
208+ use_json = use_json ,
209+ expected_status_code = expected_status_code ,
210+ ** kwargs
163211 )
164212 if not response_status_ok :
165213 _handle_error_response (response_data )
0 commit comments