Do I need to refresh the "access token" when authenticating to Google APIs as a Service Account?

158 views Asked by At

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.

1

There are 1 answers

2
Linda Lawton - DaImTo On

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.