@@ -20,7 +20,7 @@ import os = require('os');
20
20
import path = require( 'path' ) ;
21
21
22
22
import { AppErrorCodes , FirebaseAppError } from '../utils/error' ;
23
- import { HttpClient , HttpRequestConfig } from '../utils/api-request' ;
23
+ import { HttpClient , HttpRequestConfig , HttpError , HttpResponse } from '../utils/api-request' ;
24
24
import { Agent } from 'http' ;
25
25
26
26
const GOOGLE_TOKEN_AUDIENCE = 'https://accounts.google.com/o/oauth2/token' ;
@@ -190,28 +190,43 @@ export interface GoogleOAuthAccessToken {
190
190
function requestAccessToken ( client : HttpClient , request : HttpRequestConfig ) : Promise < GoogleOAuthAccessToken > {
191
191
return client . send ( request ) . then ( ( resp ) => {
192
192
const json = resp . data ;
193
- if ( json . error ) {
194
- let errorMessage = 'Error fetching access token: ' + json . error ;
195
- if ( json . error_description ) {
196
- errorMessage += ' (' + json . error_description + ')' ;
197
- }
198
- throw new FirebaseAppError ( AppErrorCodes . INVALID_CREDENTIAL , errorMessage ) ;
199
- } else if ( ! json . access_token || ! json . expires_in ) {
193
+ if ( ! json . access_token || ! json . expires_in ) {
200
194
throw new FirebaseAppError (
201
195
AppErrorCodes . INVALID_CREDENTIAL ,
202
196
`Unexpected response while fetching access token: ${ JSON . stringify ( json ) } ` ,
203
197
) ;
204
- } else {
205
- return json ;
206
198
}
199
+ return json ;
207
200
} ) . catch ( ( err ) => {
208
- throw new FirebaseAppError (
209
- AppErrorCodes . INVALID_CREDENTIAL ,
210
- `Failed to parse access token response: ${ err . toString ( ) } ` ,
211
- ) ;
201
+ throw new FirebaseAppError ( AppErrorCodes . INVALID_CREDENTIAL , getErrorMessage ( err ) ) ;
212
202
} ) ;
213
203
}
214
204
205
+ /**
206
+ * Constructs a human-readable error message from the given Error.
207
+ */
208
+ function getErrorMessage ( err : Error ) : string {
209
+ const detail : string = ( err instanceof HttpError ) ? getDetailFromResponse ( err . response ) : err . message ;
210
+ return `Error fetching access token: ${ detail } ` ;
211
+ }
212
+
213
+ /**
214
+ * Extracts details from the given HTTP error response, and returns a human-readable description. If
215
+ * the response is JSON-formatted, looks up the error and error_description fields sent by the
216
+ * Google Auth servers. Otherwise returns the entire response payload as the error detail.
217
+ */
218
+ function getDetailFromResponse ( response : HttpResponse ) : string {
219
+ if ( response . isJson ( ) && response . data . error ) {
220
+ const json = response . data ;
221
+ let detail = json . error ;
222
+ if ( json . error_description ) {
223
+ detail += ' (' + json . error_description + ')' ;
224
+ }
225
+ return detail ;
226
+ }
227
+ return response . text ;
228
+ }
229
+
215
230
/**
216
231
* Implementation of Credential that uses a service account certificate.
217
232
*/
0 commit comments