With the upgrade of google-auth-library and the refactor to use entirely googleapis-common, setting credentials on any auth client used in a GoogleApi instance has side effects on all other clients.
See the following code:
const { GoogleApis } = require('googleapis');
function client(value) {
let auth;
let client = new GoogleApis();
auth = new client.auth.OAuth2({
clientId: value,
clientSecret: value
});
auth.setCredentials({ access_token: value });
return {
client: client.gmail({
version: 'v1',
auth
}),
auth
};
}
function request(client) {
return new Promise((resolve, reject) => {
client.users.drafts.get({ userId: 'me' }).then(resolve).catch(reject)
});
}
async function checkAuth() {
const { client: a, auth: authA } = client('1');
const { client: b, auth: authB } = client('2');
try { await request(a); } catch (e) {}
authB.setCredentials({ access_token: '3' });
try { await request(a); } catch (e) {}
}
checkAuth().then(() => process.exit(0)).catch((e) => { console.log(e); process.exit(1); })
In this example, if you print the credentials of the authClient used in each request, you'll see that while we use client a in both requests, it actually uses the credentials set in client b (console.log(authClient.credentials) there outputs: {access_token:'2'}). This is a result of using GoogleAuth as a singleton, pointed out in both these issues:
This means that if the same event loop happens to interleave creation of a google client with one authorization and making a request with another, it'll use the last authorization credentials set before the request rather than the authorization credentials we passed into the initial client.
Conversely, if we create and set the auth client on a last, we'll update the access token used in the request for b to'3'.
async function checkAuth() {
const { client: b, auth: authB } = client('2');
const { client: a, auth: authA } = client('1');
try { await request(a); } catch (e) {}
authA.setCredentials({ access_token: '3' });
try { await request(b); } catch (e) {}
}
checkAuth().then(() => process.exit(0)).catch((e) => { console.log(e); process.exit(1); })
This bug requires an urgent patch as the behavior is unexpected and can produce potentially hazardous results in situations where interleaving execution of the googleapis module may happen and is unexpected given both a new client and auth client are created.
With the upgrade of
google-auth-libraryand the refactor to use entirelygoogleapis-common, setting credentials on any auth client used in aGoogleApiinstance has side effects on all other clients.See the following code:
In this example, if you print the credentials of the
authClientused in each request, you'll see that while we use clientain both requests, it actually uses the credentials set in clientb(console.log(authClient.credentials)there outputs:{access_token:'2'}). This is a result of usingGoogleAuthas a singleton, pointed out in both these issues:This means that if the same event loop happens to interleave creation of a google client with one authorization and making a request with another, it'll use the last authorization credentials set before the request rather than the authorization credentials we passed into the initial client.
Conversely, if we create and set the auth client on
alast, we'll update the access token used in the request forbto'3'.This bug requires an urgent patch as the behavior is unexpected and can produce potentially hazardous results in situations where interleaving execution of the
googleapismodule may happen and is unexpected given both a new client and auth client are created.