I am writing a NodeJS app on Google AppEngine that uses a Service Account (SA) to call a Google API (specifically the Drive API) to access a resource. I've accessed Google APIs before using OAuth2, but usually for an actual end-user in Workspace. Hence I'm most familiar with the concept of refresh tokens and access tokens, where the short-lived access token should be renewed when it expires (~ 1 hr) via use of the refresh token.
Accessing via a Service Account is new to me. From what I understand, there is no need for a refresh token (indeed one is not provided). You just re-authenticate whenever the SA's OAuth access token expires (also 1 hr). But I can't figure out how to (1) obtain and cache the access token and associated credentials, and (2) tell when they've expired so I can refresh them when necessary.
I did get my Drive access working just fine using the code below, but my concern is that this code is basically getting/refreshing a new token every time I call it, rather than instead only doing so when the credentials it got previously have expired. That can't be best-practice, and I also worry Google may not like this in the long-run if my app starts getting a lot of traffic.
I'd appreciate any help in figuring out how to do this correctly, or if I actually am fine with my current method and don't need to change anything.
// Get latest access credentials to pass to Google Drive API via 'auth' param.
// Takes as input 'saKey', which has service account's email & private key (loaded elsewhere)
async function getAccessCreds(saKey) {
let googleAuth;
let authClient;
// Returns a GoogleAuth object:
// https://cloud.google.com/nodejs/docs/reference/google-auth-library/latest/google-auth-library/googleauth
googleAuth = new GoogleAuth({
credentials: {
client_email: saKey.client_email,
private_key: saKey.private_key,
},
scopes: 'https://www.googleapis.com/auth/drive.readonly'
});
// Call googAuth.getClient() which returns a JWT object (?):
// https://cloud.google.com/nodejs/docs/reference/google-auth-library/latest/google-auth-library/jwt
authClient = googleAuth.getClient();
return authClient;
}
let saKey = loadSAKey();
let accessCreds = await getAccessCreds(saKey);
// Call Drive API
drive.files.get(
{ auth:accessCreds, fileId: fileId, alt: 'media' },
{ responseType: 'stream' }
).then(...)
As stated, the code works as written, I'm just not sure if it's best-practice or scaleable.
You are using the google apis node.js client library this library was created by google and is designed to handle all the authorization for you.
As far as a service account goes they fetch authorization when they needed it and its again all handled for you by the library.