Using Google Cloud Service Accounts to authenticate between your own services
If you are already using a Google Cloud (or Firebase) service account to access Google or Firebase APIs, you can also use the same service account to authenticate requests between your own services (machine-to-machine authentication).
Why?
When developing a solution with different services, oftentimes you want Service A to be able to securely call Service B.
- You could use a shared secret, but then you have to manage that secret.
- You could use a public/private key pair, but when you rotate the keys in Service A you also have to update the public key in Service B to trust the new credentials.
- You could make Service A publish a JWKS (JSON Web Key Set) and have Service B fetch the new signing keys periodically, but then Service A has to manage the JWKS.
- Or you can reuse a Google Cloud service account that you already have.
In Node.js, you can use google-auth-library
to get an ID token for a service account:
import { GoogleAuth } from "google-auth-library";
/**
* @param {string} audience
*/
async function getServiceAccountIdToken(audience) {
const auth = new GoogleAuth();
const client = await auth.getClient();
if (!("fetchIdToken" in client)) throw new Error("No fetchIdToken");
const token = await client.fetchIdToken(audience);
return token;
}
Make sure your service account has the Service Account OpenID Connect Identity Token Creator or Service Account Token Creator role.
The result is a Google-issued, RS256-signed JWT that you can pass to your own services. The JWT contain these claims:
{
"aud": "https://example.com",
"azp": "oidc-testing@myproject.iam.gserviceaccount.com",
"email": "oidc-testing@myproject.iam.gserviceaccount.com",
"email_verified": true,
"exp": 1686418117,
"iat": 1686414517,
"iss": "https://accounts.google.com",
"sub": "111111111111111111111"
}
The receiving service can use Google’s public keys to verify the JWT’s signature and check the aud
claim to ensure that the token was intended for it.