Skip to content

Commit 5ac6705

Browse files
authored
feat: Unify Base AuthClient Options (#1663)
* feat: Expose `Gaxios` instance and default * feat: Unify Base `AuthClient` Options * docs: clean up documentation * chore: Discourage external use via `@internal` * refactor: minor * refactor: clean up `transporter` interface, options, and docs * Merge branch 'main' of github.com:googleapis/google-auth-library-nodejs into authclient-enhancements * Merge branch 'main' of github.com:googleapis/google-auth-library-nodejs into authclient-enhancements * test: Init tests for `AuthClient` * fix: Use entire `JWT` to create accurate `createScoped` * chore: update `typescript` in fixtures * test: Use Sinon Fake Timer to Avoid Flaky Time Issue (#1667) * test: Use Sinon Fake Timer to Avoid Flaky Time Issue * chore: change order for clarity * docs(sample): Improve `keepAlive` sample with `transporterOptions` * docs: Docs-deprecate `additionalOptions` * refactor: un-alias `getOriginalOrCamel` * chore: remove confusing duplicate interface * docs: nit * docs: Improve camelCased option documentation We can refactor once microsoft/TypeScript#50715 has been resolved. * refactor: Unify `OriginalAndCamel` & `SnakeToCamelObject` + make recursive * docs: Add issue tracking link * refactor: Replace `getOriginalOrCamel` with a cleaner API * feat: Allow optional `obj` * refactor: re-add `SnakeToCamelObject` * refactor: dedupe interface for now * feat: Add camelCase options for `IdentityPoolClient`
1 parent edb9401 commit 5ac6705

22 files changed

+566
-218
lines changed

samples/keepalive.js

Lines changed: 11 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -30,21 +30,26 @@ const https = require('https');
3030
* Acquire a client, and make a request to an API that's enabled by default.
3131
*/
3232
async function main() {
33+
// create a new agent with keepAlive enabled.
34+
const agent = new https.Agent({keepAlive: true});
35+
3336
const auth = new GoogleAuth({
3437
scopes: 'https://www.googleapis.com/auth/cloud-platform',
38+
clientOptions: {
39+
transporterOptions: {
40+
agent,
41+
},
42+
},
3543
});
3644
const client = await auth.getClient();
3745
const projectId = await auth.getProjectId();
3846
const url = `https://dns.googleapis.com/dns/v1/projects/${projectId}`;
3947

40-
// create a new agent with keepAlive enabled
41-
const agent = new https.Agent({keepAlive: true});
42-
43-
// use the agent as an Axios config param to make the request
44-
const res = await client.request({url, agent});
48+
// the agent uses the provided agent.
49+
const res = await client.request({url});
4550
console.log(res.data);
4651

47-
// Re-use the same agent to make the next request over the same connection
52+
// Can also use another agent per-request.
4853
const res2 = await client.request({url, agent});
4954
console.log(res2.data);
5055
}

src/auth/authclient.ts

Lines changed: 124 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -13,31 +13,116 @@
1313
// limitations under the License.
1414

1515
import {EventEmitter} from 'events';
16-
import {GaxiosOptions, GaxiosPromise, GaxiosResponse} from 'gaxios';
16+
import {Gaxios, GaxiosOptions, GaxiosPromise, GaxiosResponse} from 'gaxios';
1717

1818
import {DefaultTransporter, Transporter} from '../transporters';
1919
import {Credentials} from './credentials';
2020
import {Headers} from './oauth2client';
21+
import {OriginalAndCamel, originalOrCamelOptions} from '../util';
2122

2223
/**
23-
* Defines the root interface for all clients that generate credentials
24-
* for calling Google APIs. All clients should implement this interface.
24+
* Base auth configurations (e.g. from JWT or `.json` files) with conventional
25+
* camelCased options.
26+
*
27+
* @privateRemarks
28+
*
29+
* This interface is purposely not exported so that it can be removed once
30+
* {@link https://github.com/microsoft/TypeScript/issues/50715} has been
31+
* resolved. Then, we can use {@link OriginalAndCamel} to shrink this interface.
32+
*
33+
* Tracking: {@link https://github.com/googleapis/google-auth-library-nodejs/issues/1686}
2534
*/
26-
export interface CredentialsClient {
35+
interface AuthJSONOptions {
2736
/**
2837
* The project ID corresponding to the current credentials if available.
2938
*/
30-
projectId?: string | null;
39+
project_id: string | null;
40+
/**
41+
* An alias for {@link AuthJSONOptions.project_id `project_id`}.
42+
*/
43+
projectId: AuthJSONOptions['project_id'];
44+
45+
/**
46+
* The quota project ID. The quota project can be used by client libraries for the billing purpose.
47+
* See {@link https://cloud.google.com/docs/quota Working with quotas}
48+
*/
49+
quota_project_id: string;
50+
51+
/**
52+
* An alias for {@link AuthJSONOptions.quota_project_id `quota_project_id`}.
53+
*/
54+
quotaProjectId: AuthJSONOptions['quota_project_id'];
55+
56+
/**
57+
* The default service domain for a given Cloud universe.
58+
*/
59+
universe_domain: string;
60+
61+
/**
62+
* An alias for {@link AuthJSONOptions.universe_domain `universe_domain`}.
63+
*/
64+
universeDomain: AuthJSONOptions['universe_domain'];
65+
}
66+
67+
/**
68+
* Base `AuthClient` configuration.
69+
*
70+
* The camelCased options are aliases of the snake_cased options, supporting both
71+
* JSON API and JS conventions.
72+
*/
73+
export interface AuthClientOptions
74+
extends Partial<OriginalAndCamel<AuthJSONOptions>> {
75+
credentials?: Credentials;
76+
77+
/**
78+
* A `Gaxios` or `Transporter` instance to use for `AuthClient` requests.
79+
*/
80+
transporter?: Gaxios | Transporter;
81+
82+
/**
83+
* Provides default options to the transporter, such as {@link GaxiosOptions.agent `agent`} or
84+
* {@link GaxiosOptions.retryConfig `retryConfig`}.
85+
*/
86+
transporterOptions?: GaxiosOptions;
3187

3288
/**
33-
* The expiration threshold in milliseconds before forcing token refresh.
89+
* The expiration threshold in milliseconds before forcing token refresh of
90+
* unexpired tokens.
3491
*/
35-
eagerRefreshThresholdMillis: number;
92+
eagerRefreshThresholdMillis?: number;
3693

3794
/**
38-
* Whether to force refresh on failure when making an authorization request.
95+
* Whether to attempt to refresh tokens on status 401/403 responses
96+
* even if an attempt is made to refresh the token preemptively based
97+
* on the expiry_date.
3998
*/
40-
forceRefreshOnFailure: boolean;
99+
forceRefreshOnFailure?: boolean;
100+
}
101+
102+
/**
103+
* The default cloud universe
104+
*
105+
* @see {@link AuthJSONOptions.universe_domain}
106+
*/
107+
export const DEFAULT_UNIVERSE = 'googleapis.com';
108+
109+
/**
110+
* The default {@link AuthClientOptions.eagerRefreshThresholdMillis}
111+
*/
112+
export const DEFAULT_EAGER_REFRESH_THRESHOLD_MILLIS = 5 * 60 * 1000;
113+
114+
/**
115+
* Defines the root interface for all clients that generate credentials
116+
* for calling Google APIs. All clients should implement this interface.
117+
*/
118+
export interface CredentialsClient {
119+
projectId?: AuthClientOptions['projectId'];
120+
eagerRefreshThresholdMillis: NonNullable<
121+
AuthClientOptions['eagerRefreshThresholdMillis']
122+
>;
123+
forceRefreshOnFailure: NonNullable<
124+
AuthClientOptions['forceRefreshOnFailure']
125+
>;
41126

42127
/**
43128
* @return A promise that resolves with the current GCP access token
@@ -88,16 +173,42 @@ export abstract class AuthClient
88173
extends EventEmitter
89174
implements CredentialsClient
90175
{
176+
projectId?: string | null;
91177
/**
92178
* The quota project ID. The quota project can be used by client libraries for the billing purpose.
93-
* See {@link https://cloud.google.com/docs/quota| Working with quotas}
179+
* See {@link https://cloud.google.com/docs/quota Working with quotas}
94180
*/
95181
quotaProjectId?: string;
96-
transporter: Transporter = new DefaultTransporter();
182+
transporter: Transporter;
97183
credentials: Credentials = {};
98-
projectId?: string | null;
99-
eagerRefreshThresholdMillis = 5 * 60 * 1000;
184+
eagerRefreshThresholdMillis = DEFAULT_EAGER_REFRESH_THRESHOLD_MILLIS;
100185
forceRefreshOnFailure = false;
186+
universeDomain = DEFAULT_UNIVERSE;
187+
188+
constructor(opts: AuthClientOptions = {}) {
189+
super();
190+
191+
const options = originalOrCamelOptions(opts);
192+
193+
// Shared auth options
194+
this.projectId = options.get('project_id') ?? null;
195+
this.quotaProjectId = options.get('quota_project_id');
196+
this.credentials = options.get('credentials') ?? {};
197+
this.universeDomain = options.get('universe_domain') ?? DEFAULT_UNIVERSE;
198+
199+
// Shared client options
200+
this.transporter = opts.transporter ?? new DefaultTransporter();
201+
202+
if (opts.transporterOptions) {
203+
this.transporter.defaults = opts.transporterOptions;
204+
}
205+
206+
if (opts.eagerRefreshThresholdMillis) {
207+
this.eagerRefreshThresholdMillis = opts.eagerRefreshThresholdMillis;
208+
}
209+
210+
this.forceRefreshOnFailure = opts.forceRefreshOnFailure ?? false;
211+
}
101212

102213
/**
103214
* Provides an alternative Gaxios request implementation with auth credentials

src/auth/awsclient.ts

Lines changed: 10 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -19,7 +19,8 @@ import {
1919
BaseExternalAccountClient,
2020
BaseExternalAccountClientOptions,
2121
} from './baseexternalclient';
22-
import {RefreshOptions, Headers} from './oauth2client';
22+
import {Headers} from './oauth2client';
23+
import {AuthClientOptions} from './authclient';
2324

2425
/**
2526
* AWS credentials JSON interface. This is used for AWS workloads.
@@ -81,11 +82,15 @@ export class AwsClient extends BaseExternalAccountClient {
8182
* An error is thrown if the credential is not a valid AWS credential.
8283
* @param options The external account options object typically loaded
8384
* from the external account JSON credential file.
84-
* @param additionalOptions Optional additional behavior customization
85-
* options. These currently customize expiration threshold time and
86-
* whether to retry on 401/403 API request errors.
85+
* @param additionalOptions **DEPRECATED, all options are available in the
86+
* `options` parameter.** Optional additional behavior customization options.
87+
* These currently customize expiration threshold time and whether to retry
88+
* on 401/403 API request errors.
8789
*/
88-
constructor(options: AwsClientOptions, additionalOptions?: RefreshOptions) {
90+
constructor(
91+
options: AwsClientOptions,
92+
additionalOptions?: AuthClientOptions
93+
) {
8994
super(options, additionalOptions);
9095
this.environmentId = options.credential_source.environment_id;
9196
// This is only required if the AWS region is not available in the

0 commit comments

Comments
 (0)