Skip to content

Commit f23e807

Browse files
feat!: Request Revamp (#1938)
* chore: update `gaxios` * refactor!: Request Revamp * style: lint * 🦉 Updates from OwlBot post-processor See https://github.com/googleapis/repo-automation-bots/blob/main/packages/owl-bot/README.md * 🦉 Updates from OwlBot post-processor See https://github.com/googleapis/repo-automation-bots/blob/main/packages/owl-bot/README.md * fix: Node 18-related fixes `Headers` in Node v18 are not case-insensitive * 🦉 Updates from OwlBot post-processor See https://github.com/googleapis/repo-automation-bots/blob/main/packages/owl-bot/README.md --------- Co-authored-by: Owl Bot <gcf-owl-bot[bot]@users.noreply.github.com>
1 parent dbcc44b commit f23e807

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

42 files changed

+795
-762
lines changed

.readme-partials.yaml

+2-2
Original file line numberDiff line numberDiff line change
@@ -56,7 +56,7 @@ body: |-
5656
5757
## OAuth2
5858
59-
This library comes with an [OAuth2](https://developers.google.com/identity/protocols/OAuth2) client that allows you to retrieve an access token and refreshes the token and retry the request seamlessly if you also provide an `expiry_date` and the token is expired. The basics of Google's OAuth2 implementation is explained on [Google Authorization and Authentication documentation](https://developers.google.com/accounts/docs/OAuth2Login).
59+
This library comes with an [OAuth2](https://developers.google.com/identity/protocols/OAuth2) client that allows you to retrieve an access token and refreshes the token and retry the request seamlessly if you also provide an `expiry_date` and the token is expired. The basics of Google's OAuth2 implementation is explained on [Google authorization and Authentication documentation](https://developers.google.com/accounts/docs/OAuth2Login).
6060
6161
In the following examples, you may need a `CLIENT_ID`, `CLIENT_SECRET` and `REDIRECT_URL`. You can find these pieces of information by going to the [Developer Console](https://console.cloud.google.com/), clicking your project > APIs & auth > credentials.
6262
@@ -1185,7 +1185,7 @@ body: |-
11851185
11861186
// Get impersonated credentials:
11871187
const authHeaders = await targetClient.getRequestHeaders();
1188-
// Do something with `authHeaders.Authorization`.
1188+
// Do something with `authHeaders.get('authorization')`.
11891189
11901190
// Use impersonated credentials:
11911191
const url = 'https://www.googleapis.com/storage/v1/b?project=anotherProjectID'

README.md

+2-2
Original file line numberDiff line numberDiff line change
@@ -100,7 +100,7 @@ main().catch(console.error);
100100

101101
## OAuth2
102102

103-
This library comes with an [OAuth2](https://developers.google.com/identity/protocols/OAuth2) client that allows you to retrieve an access token and refreshes the token and retry the request seamlessly if you also provide an `expiry_date` and the token is expired. The basics of Google's OAuth2 implementation is explained on [Google Authorization and Authentication documentation](https://developers.google.com/accounts/docs/OAuth2Login).
103+
This library comes with an [OAuth2](https://developers.google.com/identity/protocols/OAuth2) client that allows you to retrieve an access token and refreshes the token and retry the request seamlessly if you also provide an `expiry_date` and the token is expired. The basics of Google's OAuth2 implementation is explained on [Google authorization and Authentication documentation](https://developers.google.com/accounts/docs/OAuth2Login).
104104

105105
In the following examples, you may need a `CLIENT_ID`, `CLIENT_SECRET` and `REDIRECT_URL`. You can find these pieces of information by going to the [Developer Console](https://console.cloud.google.com/), clicking your project > APIs & auth > credentials.
106106

@@ -1229,7 +1229,7 @@ async function main() {
12291229

12301230
// Get impersonated credentials:
12311231
const authHeaders = await targetClient.getRequestHeaders();
1232-
// Do something with `authHeaders.Authorization`.
1232+
// Do something with `authHeaders.get('authorization')`.
12331233

12341234
// Use impersonated credentials:
12351235
const url = 'https://www.googleapis.com/storage/v1/b?project=anotherProjectID'

browser-test/test.oauth2.ts

+2-2
Original file line numberDiff line numberDiff line change
@@ -46,10 +46,10 @@ const FEDERATED_SIGNON_JWK_CERTS = [
4646
},
4747
];
4848
const FEDERATED_SIGNON_JWK_CERTS_AXIOS_RESPONSE = {
49-
headers: {
49+
headers: new Headers({
5050
'cache-control':
5151
'cache-control: public, max-age=24000, must-revalidate, no-transform',
52-
},
52+
}),
5353
data: {keys: FEDERATED_SIGNON_JWK_CERTS},
5454
};
5555

package.json

+5-6
Original file line numberDiff line numberDiff line change
@@ -19,9 +19,9 @@
1919
"dependencies": {
2020
"base64-js": "^1.3.0",
2121
"ecdsa-sig-formatter": "^1.0.11",
22-
"gaxios": "^6.1.1",
23-
"gcp-metadata": "^6.1.0",
24-
"gtoken": "^7.0.0",
22+
"gaxios": "^7.0.0-rc.4",
23+
"gcp-metadata": "^7.0.0-rc.1",
24+
"gtoken": "^8.0.0-rc.1",
2525
"jws": "^4.0.0"
2626
},
2727
"devDependencies": {
@@ -54,7 +54,7 @@
5454
"mocha": "^9.2.2",
5555
"mv": "^2.1.1",
5656
"ncp": "^2.0.0",
57-
"nock": "^13.0.0",
57+
"nock": "^14.0.1",
5858
"null-loader": "^4.0.0",
5959
"puppeteer": "^24.0.0",
6060
"sinon": "^18.0.0",
@@ -84,8 +84,7 @@
8484
"browser-test": "karma start",
8585
"docs-test": "linkinator docs",
8686
"predocs-test": "npm run docs",
87-
"prelint": "cd samples; npm link ../; npm install",
88-
"precompile": "gts clean"
87+
"prelint": "cd samples; npm link ../; npm install"
8988
},
9089
"license": "Apache-2.0"
9190
}

samples/idTokenFromMetadataServer.js

+1-1
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,7 @@
1414

1515
/**
1616
* Uses the Google Cloud metadata server environment to create an identity token
17-
* and add it to the HTTP request as part of an Authorization header.
17+
* and add it to the HTTP request as part of an authorization header.
1818
*
1919
* @param {string} targetAudience - The url or target audience to obtain the ID token for.
2020
*/

samples/test/externalclient.test.js

+2-2
Original file line numberDiff line numberDiff line change
@@ -356,15 +356,15 @@ describe('samples for external-account', () => {
356356
if (req.url === '/token' && req.method === 'GET') {
357357
// Confirm expected header is passed along the request.
358358
if (req.headers['my-header'] === 'some-value') {
359-
res.setHeader('Content-Type', 'application/json');
359+
res.setHeader('content-type', 'application/json');
360360
res.writeHead(200);
361361
res.end(
362362
JSON.stringify({
363363
access_token: oidcToken,
364364
})
365365
);
366366
} else {
367-
res.setHeader('Content-Type', 'application/json');
367+
res.setHeader('content-type', 'application/json');
368368
res.writeHead(400);
369369
res.end(
370370
JSON.stringify({

src/auth/authclient.ts

+44-19
Original file line numberDiff line numberDiff line change
@@ -160,10 +160,10 @@ export interface CredentialsClient {
160160
* resolves with authorization header fields.
161161
*
162162
* The result has the form:
163-
* { Authorization: 'Bearer <access_token_value>' }
163+
* { authorization: 'Bearer <access_token_value>' }
164164
* @param url The URI being authorized.
165165
*/
166-
getRequestHeaders(url?: string): Promise<Headers>;
166+
getRequestHeaders(url?: string | URL): Promise<Headers>;
167167

168168
/**
169169
* Provides an alternative Gaxios request implementation with auth credentials
@@ -251,10 +251,13 @@ export abstract class AuthClient
251251
* resolves with authorization header fields.
252252
*
253253
* The result has the form:
254-
* { Authorization: 'Bearer <access_token_value>' }
254+
* ```ts
255+
* new Headers({'authorization': 'Bearer <access_token_value>'});
256+
* ```
257+
*
255258
* @param url The URI being authorized.
256259
*/
257-
abstract getRequestHeaders(url?: string): Promise<Headers>;
260+
abstract getRequestHeaders(url?: string | URL): Promise<Headers>;
258261

259262
/**
260263
* @return A promise that resolves with the current GCP access token
@@ -285,35 +288,58 @@ export abstract class AuthClient
285288
// the x-goog-user-project header, to indicate an alternate account for
286289
// billing and quota:
287290
if (
288-
!headers['x-goog-user-project'] && // don't override a value the user sets.
291+
!headers.has('x-goog-user-project') && // don't override a value the user sets.
289292
this.quotaProjectId
290293
) {
291-
headers['x-goog-user-project'] = this.quotaProjectId;
294+
headers.set('x-goog-user-project', this.quotaProjectId);
292295
}
293296
return headers;
294297
}
295298

299+
/**
300+
* Adds the `x-goog-user-project` and `authorization` headers to the target Headers
301+
* object, if they exist on the source.
302+
*
303+
* @param target the headers to target
304+
* @param source the headers to source from
305+
* @returns the target headers
306+
*/
307+
protected addUserProjectAndAuthHeaders<T extends Headers>(
308+
target: T,
309+
source: Headers
310+
): T {
311+
const xGoogUserProject = source.get('x-goog-user-project');
312+
const authorizationHeader = source.get('authorization');
313+
314+
if (xGoogUserProject) {
315+
target.set('x-goog-user-project', xGoogUserProject);
316+
}
317+
318+
if (authorizationHeader) {
319+
target.set('authorization', authorizationHeader);
320+
}
321+
322+
return target;
323+
}
324+
296325
static readonly DEFAULT_REQUEST_INTERCEPTOR: Parameters<
297326
Gaxios['interceptors']['request']['add']
298327
>[0] = {
299328
resolved: async config => {
300-
const headers = config.headers || {};
301-
302329
// Set `x-goog-api-client`, if not already set
303-
if (!headers['x-goog-api-client']) {
330+
if (!config.headers.has('x-goog-api-client')) {
304331
const nodeVersion = process.version.replace(/^v/, '');
305-
headers['x-goog-api-client'] = `gl-node/${nodeVersion}`;
332+
config.headers.set('x-goog-api-client', `gl-node/${nodeVersion}`);
306333
}
307334

308335
// Set `User-Agent`
309-
if (!headers['User-Agent']) {
310-
headers['User-Agent'] = USER_AGENT;
311-
} else if (!headers['User-Agent'].includes(`${PRODUCT_NAME}/`)) {
312-
headers['User-Agent'] = `${headers['User-Agent']} ${USER_AGENT}`;
336+
const userAgent = config.headers.get('User-Agent');
337+
if (!userAgent) {
338+
config.headers.set('User-Agent', USER_AGENT);
339+
} else if (!userAgent.includes(`${PRODUCT_NAME}/`)) {
340+
config.headers.set('User-Agent', `${userAgent} ${USER_AGENT}`);
313341
}
314342

315-
config.headers = headers;
316-
317343
return config;
318344
},
319345
};
@@ -337,9 +363,8 @@ export abstract class AuthClient
337363
}
338364
}
339365

340-
export interface Headers {
341-
[index: string]: string;
342-
}
366+
// TypeScript does not have `HeadersInit` in the standard types yet
367+
export type HeadersInit = ConstructorParameters<typeof Headers>[0];
343368

344369
export interface GetAccessTokenResponse {
345370
token?: string | null;

src/auth/awsclient.ts

+8-8
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,7 @@ import {
2121

2222
import {DefaultAwsSecurityCredentialsSupplier} from './defaultawssecuritycredentialssupplier';
2323
import {originalOrCamelOptions, SnakeToCamelObject} from '../util';
24+
import {Gaxios} from 'gaxios';
2425

2526
/**
2627
* AWS credentials JSON interface. This is used for AWS workloads.
@@ -230,7 +231,7 @@ export class AwsClient extends BaseExternalAccountClient {
230231
// The GCP STS endpoint expects the headers to be formatted as:
231232
// [
232233
// {key: 'x-amz-date', value: '...'},
233-
// {key: 'Authorization', value: '...'},
234+
// {key: 'authorization', value: '...'},
234235
// ...
235236
// ]
236237
// And then serialized as:
@@ -240,7 +241,7 @@ export class AwsClient extends BaseExternalAccountClient {
240241
// headers: [{key: 'x-amz-date', value: '...'}, ...]
241242
// }))
242243
const reformattedHeader: {key: string; value: string}[] = [];
243-
const extendedHeaders = Object.assign(
244+
const extendedHeaders = Gaxios.mergeHeaders(
244245
{
245246
// The full, canonical resource name of the workload identity pool
246247
// provider, with or without the HTTPS prefix.
@@ -250,13 +251,12 @@ export class AwsClient extends BaseExternalAccountClient {
250251
},
251252
options.headers
252253
);
254+
253255
// Reformat header to GCP STS expected format.
254-
for (const key in extendedHeaders) {
255-
reformattedHeader.push({
256-
key,
257-
value: extendedHeaders[key],
258-
});
259-
}
256+
extendedHeaders.forEach((value, key) =>
257+
reformattedHeader.push({key, value})
258+
);
259+
260260
// Serialize the reformatted signed request.
261261
return encodeURIComponent(
262262
JSON.stringify({

0 commit comments

Comments
 (0)