Skip to content

Commit 0eee7e9

Browse files
authored
Merge branch 'main' into owl-bot-update-lock-54d3915b7c06c51f4339072d9ae9ddec43fe3197d5dd45122ca6ab7a02168765
2 parents 557da2c + dbcc44b commit 0eee7e9

28 files changed

+449
-496
lines changed

Diff for: package.json

+2-2
Original file line numberDiff line numberDiff line change
@@ -34,7 +34,7 @@
3434
"@types/node": "^22.0.0",
3535
"@types/sinon": "^17.0.0",
3636
"assert-rejects": "^1.0.0",
37-
"c8": "^8.0.0",
37+
"c8": "^10.0.0",
3838
"chai": "^4.2.0",
3939
"codecov": "^3.0.2",
4040
"gts": "^5.0.0",
@@ -56,7 +56,7 @@
5656
"ncp": "^2.0.0",
5757
"nock": "^13.0.0",
5858
"null-loader": "^4.0.0",
59-
"puppeteer": "^21.0.0",
59+
"puppeteer": "^24.0.0",
6060
"sinon": "^18.0.0",
6161
"ts-loader": "^8.0.0",
6262
"typescript": "^5.1.6",

Diff for: samples/puppeteer/package.json

+1-1
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,6 @@
1212
"license": "Apache-2.0",
1313
"dependencies": {
1414
"google-auth-library": "^9.0.0",
15-
"puppeteer": "^21.0.0"
15+
"puppeteer": "^24.0.0"
1616
}
1717
}

Diff for: samples/test/externalclient.test.js

+11-10
Original file line numberDiff line numberDiff line change
@@ -72,11 +72,7 @@ const {assert} = require('chai');
7272
const {describe, it, before, afterEach} = require('mocha');
7373
const fs = require('fs');
7474
const {promisify} = require('util');
75-
const {
76-
GoogleAuth,
77-
DefaultTransporter,
78-
IdentityPoolClient,
79-
} = require('google-auth-library');
75+
const {GoogleAuth, IdentityPoolClient, gaxios} = require('google-auth-library');
8076
const os = require('os');
8177
const path = require('path');
8278
const http = require('http');
@@ -158,11 +154,16 @@ const assumeRoleWithWebIdentity = async (
158154
// been configured:
159155
// https://docs.aws.amazon.com/IAM/latest/UserGuide/id_roles_create_for-idp_oidc.html
160156
const oidcToken = await generateGoogleIdToken(auth, aud, clientEmail);
161-
const transporter = new DefaultTransporter();
162-
const url =
163-
'https://sts.amazonaws.com/?Action=AssumeRoleWithWebIdentity' +
164-
'&Version=2011-06-15&DurationSeconds=3600&RoleSessionName=nodejs-test' +
165-
`&RoleArn=${awsRoleArn}&WebIdentityToken=${oidcToken}`;
157+
const transporter = new gaxios.Gaxios();
158+
159+
const url = new URL('https://sts.amazonaws.com/');
160+
url.searchParams.append('Action', 'AssumeRoleWithWebIdentity');
161+
url.searchParams.append('Version', '2011-06-15');
162+
url.searchParams.append('DurationSeconds', '3600');
163+
url.searchParams.append('RoleSessionName', 'nodejs-test');
164+
url.searchParams.append('RoleArn', awsRoleArn);
165+
url.searchParams.append('WebIdentityToken', oidcToken);
166+
166167
// The response is in XML format but we will parse it as text.
167168
const response = await transporter.request({url, responseType: 'text'});
168169
const rawXml = response.data;

Diff for: src/auth/authclient.ts

+65-28
Original file line numberDiff line numberDiff line change
@@ -15,10 +15,11 @@
1515
import {EventEmitter} from 'events';
1616
import {Gaxios, GaxiosOptions, GaxiosPromise, GaxiosResponse} from 'gaxios';
1717

18-
import {DefaultTransporter, Transporter} from '../transporters';
1918
import {Credentials} from './credentials';
2019
import {OriginalAndCamel, originalOrCamelOptions} from '../util';
2120

21+
import {PRODUCT_NAME, USER_AGENT} from '../shared.cjs';
22+
2223
/**
2324
* Base auth configurations (e.g. from JWT or `.json` files) with conventional
2425
* camelCased options.
@@ -81,13 +82,17 @@ export interface AuthClientOptions
8182
credentials?: Credentials;
8283

8384
/**
84-
* A `Gaxios` or `Transporter` instance to use for `AuthClient` requests.
85+
* The {@link Gaxios `Gaxios`} instance used for making requests.
86+
*
87+
* @see {@link AuthClientOptions.useAuthRequestParameters}
8588
*/
86-
transporter?: Gaxios | Transporter;
89+
transporter?: Gaxios;
8790

8891
/**
8992
* Provides default options to the transporter, such as {@link GaxiosOptions.agent `agent`} or
9093
* {@link GaxiosOptions.retryConfig `retryConfig`}.
94+
*
95+
* This option is ignored if {@link AuthClientOptions.transporter `gaxios`} has been provided
9196
*/
9297
transporterOptions?: GaxiosOptions;
9398

@@ -103,6 +108,19 @@ export interface AuthClientOptions
103108
* on the expiry_date.
104109
*/
105110
forceRefreshOnFailure?: boolean;
111+
112+
/**
113+
* Enables/disables the adding of the AuthClient's default interceptor.
114+
*
115+
* @see {@link AuthClientOptions.transporter}
116+
*
117+
* @remarks
118+
*
119+
* Disabling is useful for debugging and experimentation.
120+
*
121+
* @default true
122+
*/
123+
useAuthRequestParameters?: boolean;
106124
}
107125

108126
/**
@@ -183,7 +201,10 @@ export abstract class AuthClient
183201
* See {@link https://cloud.google.com/docs/quota Working with quotas}
184202
*/
185203
quotaProjectId?: string;
186-
transporter: Transporter;
204+
/**
205+
* The {@link Gaxios `Gaxios`} instance used for making requests.
206+
*/
207+
transporter: Gaxios;
187208
credentials: Credentials = {};
188209
eagerRefreshThresholdMillis = DEFAULT_EAGER_REFRESH_THRESHOLD_MILLIS;
189210
forceRefreshOnFailure = false;
@@ -202,10 +223,12 @@ export abstract class AuthClient
202223
this.universeDomain = options.get('universe_domain') ?? DEFAULT_UNIVERSE;
203224

204225
// Shared client options
205-
this.transporter = opts.transporter ?? new DefaultTransporter();
226+
this.transporter = opts.transporter ?? new Gaxios(opts.transporterOptions);
206227

207-
if (opts.transporterOptions) {
208-
this.transporter.defaults = opts.transporterOptions;
228+
if (options.get('useAuthRequestParameters') !== false) {
229+
this.transporter.interceptors.request.add(
230+
AuthClient.DEFAULT_REQUEST_INTERCEPTOR
231+
);
209232
}
210233

211234
if (opts.eagerRefreshThresholdMillis) {
@@ -216,29 +239,11 @@ export abstract class AuthClient
216239
}
217240

218241
/**
219-
* Return the {@link Gaxios `Gaxios`} instance from the {@link AuthClient.transporter}.
242+
* The public request API in which credentials may be added to the request.
220243
*
221-
* @expiremental
222-
*/
223-
get gaxios(): Gaxios | null {
224-
if (this.transporter instanceof Gaxios) {
225-
return this.transporter;
226-
} else if (this.transporter instanceof DefaultTransporter) {
227-
return this.transporter.instance;
228-
} else if (
229-
'instance' in this.transporter &&
230-
this.transporter.instance instanceof Gaxios
231-
) {
232-
return this.transporter.instance;
233-
}
234-
235-
return null;
236-
}
237-
238-
/**
239-
* Provides an alternative Gaxios request implementation with auth credentials
244+
* @param options options for `gaxios`
240245
*/
241-
abstract request<T>(opts: GaxiosOptions): GaxiosPromise<T>;
246+
abstract request<T>(options: GaxiosOptions): GaxiosPromise<T>;
242247

243248
/**
244249
* The main authentication interface. It takes an optional url which when
@@ -288,6 +293,31 @@ export abstract class AuthClient
288293
return headers;
289294
}
290295

296+
static readonly DEFAULT_REQUEST_INTERCEPTOR: Parameters<
297+
Gaxios['interceptors']['request']['add']
298+
>[0] = {
299+
resolved: async config => {
300+
const headers = config.headers || {};
301+
302+
// Set `x-goog-api-client`, if not already set
303+
if (!headers['x-goog-api-client']) {
304+
const nodeVersion = process.version.replace(/^v/, '');
305+
headers['x-goog-api-client'] = `gl-node/${nodeVersion}`;
306+
}
307+
308+
// 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}`;
313+
}
314+
315+
config.headers = headers;
316+
317+
return config;
318+
},
319+
};
320+
291321
/**
292322
* Retry config for Auth-related requests.
293323
*
@@ -315,3 +345,10 @@ export interface GetAccessTokenResponse {
315345
token?: string | null;
316346
res?: GaxiosResponse | null;
317347
}
348+
349+
/**
350+
* @deprecated - use the Promise API instead
351+
*/
352+
export interface BodyResponseCallback<T> {
353+
(err: Error | null, res?: GaxiosResponse<T> | null): void;
354+
}

Diff for: src/auth/baseexternalclient.ts

+9-5
Original file line numberDiff line numberDiff line change
@@ -27,8 +27,8 @@ import {
2727
AuthClientOptions,
2828
GetAccessTokenResponse,
2929
Headers,
30+
BodyResponseCallback,
3031
} from './authclient';
31-
import {BodyResponseCallback, Transporter} from '../transporters';
3232
import * as sts from './stscredentials';
3333
import {ClientAuthentication} from './oauth2common';
3434
import {SnakeToCamelObject, originalOrCamelOptions} from '../util';
@@ -110,10 +110,11 @@ export interface ExternalAccountSupplierContext {
110110
* * "urn:ietf:params:oauth:token-type:id_token"
111111
*/
112112
subjectTokenType: string;
113-
/** The {@link Gaxios} or {@link Transporter} instance from
114-
* the calling external account to use for requests.
113+
/**
114+
* The {@link Gaxios} instance for calling external account
115+
* to use for requests.
115116
*/
116-
transporter: Transporter | Gaxios;
117+
transporter: Gaxios;
117118
}
118119

119120
/**
@@ -312,7 +313,10 @@ export abstract class BaseExternalAccountClient extends AuthClient {
312313
};
313314
}
314315

315-
this.stsCredential = new sts.StsCredentials(tokenUrl, this.clientAuth);
316+
this.stsCredential = new sts.StsCredentials({
317+
tokenExchangeEndpoint: tokenUrl,
318+
clientAuthentication: this.clientAuth,
319+
});
316320
this.scopes = opts.get('scopes') || [DEFAULT_OAUTH_SCOPE];
317321
this.cachedAccessToken = null;
318322
this.audience = opts.get('audience');

Diff for: src/auth/defaultawssecuritycredentialssupplier.ts

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

1515
import {ExternalAccountSupplierContext} from './baseexternalclient';
1616
import {Gaxios, GaxiosOptions} from 'gaxios';
17-
import {Transporter} from '../transporters';
1817
import {AwsSecurityCredentialsSupplier} from './awsclient';
1918
import {AwsSecurityCredentials} from './awsrequestsigner';
2019
import {Headers} from './authclient';
@@ -183,9 +182,7 @@ export class DefaultAwsSecurityCredentialsSupplier
183182
* @param transporter The transporter to use for requests.
184183
* @return A promise that resolves with the IMDSv2 Session Token.
185184
*/
186-
async #getImdsV2SessionToken(
187-
transporter: Transporter | Gaxios
188-
): Promise<string> {
185+
async #getImdsV2SessionToken(transporter: Gaxios): Promise<string> {
189186
const opts: GaxiosOptions = {
190187
...this.additionalGaxiosOptions,
191188
url: this.imdsV2SessionTokenUrl,
@@ -205,7 +202,7 @@ export class DefaultAwsSecurityCredentialsSupplier
205202
*/
206203
async #getAwsRoleName(
207204
headers: Headers,
208-
transporter: Transporter | Gaxios
205+
transporter: Gaxios
209206
): Promise<string> {
210207
if (!this.securityCredentialsUrl) {
211208
throw new Error(
@@ -236,7 +233,7 @@ export class DefaultAwsSecurityCredentialsSupplier
236233
async #retrieveAwsSecurityCredentials(
237234
roleName: string,
238235
headers: Headers,
239-
transporter: Transporter | Gaxios
236+
transporter: Gaxios
240237
): Promise<AwsSecurityCredentialsResponse> {
241238
const response = await transporter.request<AwsSecurityCredentialsResponse>({
242239
...this.additionalGaxiosOptions,

Diff for: src/auth/downscopedclient.ts

+8-7
Original file line numberDiff line numberDiff line change
@@ -20,13 +20,13 @@ import {
2020
} from 'gaxios';
2121
import * as stream from 'stream';
2222

23-
import {BodyResponseCallback} from '../transporters';
2423
import {Credentials} from './credentials';
2524
import {
2625
AuthClient,
2726
AuthClientOptions,
2827
GetAccessTokenResponse,
2928
Headers,
29+
BodyResponseCallback,
3030
} from './authclient';
3131

3232
import * as sts from './stscredentials';
@@ -164,11 +164,12 @@ export class DownscopedClient extends AuthClient {
164164
// Check 1-10 Access Boundary Rules are defined within Credential Access
165165
// Boundary.
166166
if (
167-
credentialAccessBoundary.accessBoundary.accessBoundaryRules.length === 0
167+
this.credentialAccessBoundary.accessBoundary.accessBoundaryRules
168+
.length === 0
168169
) {
169170
throw new Error('At least one access boundary rule needs to be defined.');
170171
} else if (
171-
credentialAccessBoundary.accessBoundary.accessBoundaryRules.length >
172+
this.credentialAccessBoundary.accessBoundary.accessBoundaryRules.length >
172173
MAX_ACCESS_BOUNDARY_RULES_COUNT
173174
) {
174175
throw new Error(
@@ -179,7 +180,7 @@ export class DownscopedClient extends AuthClient {
179180

180181
// Check at least one permission should be defined in each Access Boundary
181182
// Rule.
182-
for (const rule of credentialAccessBoundary.accessBoundary
183+
for (const rule of this.credentialAccessBoundary.accessBoundary
183184
.accessBoundaryRules) {
184185
if (rule.availablePermissions.length === 0) {
185186
throw new Error(
@@ -188,9 +189,9 @@ export class DownscopedClient extends AuthClient {
188189
}
189190
}
190191

191-
this.stsCredential = new sts.StsCredentials(
192-
`https://sts.${this.universeDomain}/v1/token`
193-
);
192+
this.stsCredential = new sts.StsCredentials({
193+
tokenExchangeEndpoint: `https://sts.${this.universeDomain}/v1/token`,
194+
});
194195

195196
this.cachedDownscopedAccessToken = null;
196197
}

0 commit comments

Comments
 (0)