Skip to content

Commit

Permalink
feat: Support AuthClient for authClient (#732)
Browse files Browse the repository at this point in the history
  • Loading branch information
d-goog authored Feb 22, 2022
1 parent 6d1e19e commit d4c39f3
Show file tree
Hide file tree
Showing 6 changed files with 101 additions and 23 deletions.
2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -38,7 +38,7 @@
"duplexify": "^4.1.1",
"ent": "^2.2.0",
"extend": "^3.0.2",
"google-auth-library": "^7.9.2",
"google-auth-library": "^7.14.0",
"retry-request": "^4.2.2",
"teeny-request": "^7.0.0"
},
Expand Down
12 changes: 6 additions & 6 deletions src/service.ts
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@

import arrify = require('arrify');
import * as extend from 'extend';
import {GoogleAuth, GoogleAuthOptions} from 'google-auth-library';
import {AuthClient, GoogleAuth, GoogleAuthOptions} from 'google-auth-library';
import * as r from 'teeny-request';

import {Interceptor} from './service-object';
Expand Down Expand Up @@ -57,13 +57,13 @@ export interface ServiceConfig {
packageJson: PackageJson;

/**
* Reuse an existing GoogleAuth client instead of creating a new one.
* Reuse an existing `AuthClient` or `GoogleAuth` client instead of creating a new one.
*/
authClient?: GoogleAuth;
authClient?: AuthClient | GoogleAuth;
}

export interface ServiceOptions extends GoogleAuthOptions {
authClient?: GoogleAuth;
export interface ServiceOptions extends Omit<GoogleAuthOptions, 'authClient'> {
authClient?: AuthClient | GoogleAuth;
interceptors_?: Interceptor[];
email?: string;
token?: string;
Expand All @@ -81,7 +81,7 @@ export class Service {
private projectIdRequired: boolean;
providedUserAgent?: string;
makeAuthenticatedRequest: MakeAuthenticatedRequest;
authClient: GoogleAuth;
authClient: GoogleAuth<AuthClient>;
private getCredentials: {};
readonly apiEndpoint: string;
timeout?: number;
Expand Down
29 changes: 21 additions & 8 deletions src/util.ts
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@
import {replaceProjectIdToken} from '@google-cloud/projectify';
import * as ent from 'ent';
import * as extend from 'extend';
import {GoogleAuth, GoogleAuthOptions} from 'google-auth-library';
import {AuthClient, GoogleAuth, GoogleAuthOptions} from 'google-auth-library';
import {CredentialBody} from 'google-auth-library';
import * as r from 'teeny-request';
import * as retryRequest from 'retry-request';
Expand Down Expand Up @@ -111,7 +111,7 @@ export interface MakeAuthenticatedRequest {
getCredentials: (
callback: (err?: Error | null, credentials?: CredentialBody) => void
) => void;
authClient: GoogleAuth;
authClient: GoogleAuth<AuthClient>;
}

export interface Abortable {
Expand All @@ -125,7 +125,7 @@ export interface PackageJson {
}

export interface MakeAuthenticatedRequestFactoryConfig
extends GoogleAuthOptions {
extends Omit<GoogleAuthOptions, 'authClient'> {
/**
* Automatically retry requests if the response is related to rate limits or
* certain intermittent server errors. We will exponentially backoff
Expand Down Expand Up @@ -157,10 +157,10 @@ export interface MakeAuthenticatedRequestFactoryConfig
stream?: Duplexify;

/**
* A pre-instantiated GoogleAuth client that should be used.
* A pre-instantiated `AuthClient` or `GoogleAuth` client that should be used.
* A new will be created if this is not set.
*/
authClient?: GoogleAuth;
authClient?: AuthClient | GoogleAuth;
}

export interface MakeAuthenticatedRequestOptions {
Expand Down Expand Up @@ -591,8 +591,21 @@ export class Util {
if (googleAutoAuthConfig.projectId === '{{projectId}}') {
delete googleAutoAuthConfig.projectId;
}
const authClient =
googleAutoAuthConfig.authClient || new GoogleAuth(googleAutoAuthConfig);

let authClient: GoogleAuth<AuthClient>;

if (googleAutoAuthConfig.authClient instanceof GoogleAuth) {
// Use an existing `GoogleAuth`
authClient = googleAutoAuthConfig.authClient;
} else {
// Pass an `AuthClient` to `GoogleAuth`, if available
const config = {
...googleAutoAuthConfig,
authClient: googleAutoAuthConfig.authClient,
};

authClient = new GoogleAuth(config);
}

/**
* The returned function that will make an authenticated request.
Expand Down Expand Up @@ -659,7 +672,7 @@ export class Util {
// A projectId was required, but we don't have one.
// Re-use the "Could not load the default credentials error" if
// auto auth failed.
err = err || e;
err = err || (e as Error);
}
}

Expand Down
1 change: 1 addition & 0 deletions test/service-object.ts
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@ import * as extend from 'extend';
import * as proxyquire from 'proxyquire';
import * as r from 'teeny-request';
import * as sinon from 'sinon';
import {AuthClient, OAuth2Client} from 'google-auth-library';

import {Service} from '../src';
import * as SO from '../src/service-object';
Expand Down
41 changes: 35 additions & 6 deletions test/service.ts
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@ import {describe, it, before, beforeEach, after} from 'mocha';
import * as extend from 'extend';
import * as proxyquire from 'proxyquire';
import {Request} from 'teeny-request';
import {AuthClient, GoogleAuth, OAuth2Client} from 'google-auth-library';

import {Interceptor} from '../src';
import {ServiceConfig, ServiceOptions} from '../src/service';
Expand Down Expand Up @@ -69,7 +70,7 @@ describe('Service', () => {
};

const OPTIONS = {
authClient: {getCredentials: () => {}},
authClient: new GoogleAuth(),
credentials: {},
keyFile: {},
email: 'email',
Expand Down Expand Up @@ -130,11 +131,39 @@ describe('Service', () => {
assert.strictEqual(service.authClient, OPTIONS.authClient);
});

it('should allow passing a custom GoogleAuth client', () => {
const authClient = {getCredentials: () => {}};
const cfg = Object.assign({}, {authClient}, CONFIG);
const service = new Service(cfg);
assert.strictEqual(service.authClient, authClient);
describe('`AuthClient` support', () => {
// Using a custom `AuthClient` to ensure any `AuthClient` would work
class CustomAuthClient extends AuthClient {
async getAccessToken() {
return {token: '', res: undefined};
}

async getRequestHeaders() {
return {};
}

request = OAuth2Client.prototype.request.bind(this);
}

it('should accept an `AuthClient` passed to config', async () => {
const authClient = new CustomAuthClient();
const serviceObject = new Service({...CONFIG, authClient});

// The custom `AuthClient` should be passed to `GoogleAuth` and used internally
const client = await serviceObject.authClient.getClient();

assert.strictEqual(client, authClient);
});

it('should accept an `AuthClient` passed to options', async () => {
const authClient = new CustomAuthClient();
const serviceObject = new Service(CONFIG, {authClient});

// The custom `AuthClient` should be passed to `GoogleAuth` and used internally
const client = await serviceObject.authClient.getClient();

assert.strictEqual(client, authClient);
});
});

it('should localize the baseUrl', () => {
Expand Down
39 changes: 37 additions & 2 deletions test/util.ts
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,12 @@ import {replaceProjectIdToken} from '@google-cloud/projectify';
import * as assert from 'assert';
import {describe, it, before, beforeEach, afterEach} from 'mocha';
import * as extend from 'extend';
import {GoogleAuth, GoogleAuthOptions} from 'google-auth-library';
import {
AuthClient,
GoogleAuth,
GoogleAuthOptions,
OAuth2Client,
} from 'google-auth-library';
import * as nock from 'nock';
import * as proxyquire from 'proxyquire';
import * as r from 'teeny-request';
Expand Down Expand Up @@ -113,6 +118,18 @@ describe('common/util', () => {
}

const fakeGoogleAuth = {
// Using a custom `AuthClient` to ensure any `AuthClient` would work
AuthClient: class CustomAuthClient extends AuthClient {
async getAccessToken() {
return {token: '', res: undefined};
}

async getRequestHeaders() {
return {};
}

request = OAuth2Client.prototype.request.bind(this);
},
GoogleAuth: class {
constructor(config?: GoogleAuthOptions) {
return new GoogleAuth(config);
Expand Down Expand Up @@ -590,7 +607,7 @@ describe('common/util', () => {
const fakeStream = new stream.Writable();
const error = new Error('Error.');
fakeStream.write = () => false;
dup.end = () => {};
dup.end = () => dup;

stub('handleResp', (err, res, body, callback) => {
callback(error);
Expand Down Expand Up @@ -705,6 +722,24 @@ describe('common/util', () => {
it('should create an authClient', done => {
const config = {test: true} as MakeAuthenticatedRequestFactoryConfig;

sandbox
.stub(fakeGoogleAuth, 'GoogleAuth')
.callsFake((config_: GoogleAuthOptions) => {
assert.deepStrictEqual(config_, {...config, authClient: undefined});
setImmediate(done);
return authClient;
});

util.makeAuthenticatedRequestFactory(config);
});

it('should pass an `AuthClient` to `GoogleAuth` when provided', done => {
const customAuthClient = new fakeGoogleAuth.AuthClient();

const config: MakeAuthenticatedRequestFactoryConfig = {
authClient: customAuthClient,
};

sandbox
.stub(fakeGoogleAuth, 'GoogleAuth')
.callsFake((config_: GoogleAuthOptions) => {
Expand Down

0 comments on commit d4c39f3

Please sign in to comment.