Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Firebase ID token has incorrect "aud" (audience) claim when calling from Endpoint connected to Google Functions

I am using Google Endpoints as an API gateway which is running in a Google Run container service. The API path points to a Google Function (node js). The calls to the API gateway are from a web application (viz. browser).

One of the paths is: /login which authenticates a user in firebase using the firebase.auth().signInWithEmailAndPassword method. I get the token Id of the user and send it back in the response header (authentication bearer) back to the browser. This works as expected.

When other Requests are made (e.g /check) to the endpoint the token (in the header) is included. I wanted to check the validity of the token using the Firebase Admin method before processing any requests. The code in the Google Function that does this for one of the routes is as follows:

...

const decodeIdToken = async (req, res, next) => {
  // Read the ID Token from the Authorization header.
  const idToken = req.headers.authorization.split('Bearer ')[1];
  try {
    const decodedIdToken = await admin.auth().verifyIdToken(idToken);
    req.decodedToken = decodedIdToken;
    next();
    return;
  } catch (error) {
    return res.status(403).json({
      status: 'failure',
      data: null,
      error: error.message
    });
  }
};

// use decodeIdToken as middleware
app.post('/check', decodeIdToken, (req, res, next) => {
  return res.json({
    status: 'success',
    data: req.decodedToken,
    error: null
  });
});

When I call (via Postman ) the routes by directly calling the Google Function trigger both the routes work. However, when I call the Google Endpoints which point to the Google Function I receive the following error while using the Firebase Admin object:

Firebase ID token has incorrect \"aud\" (audience) claim. Expected \"PROJECT-ID\" but got \"https://us-central1-PROJECT-ID.cloudfunctions.net/FUNCTION-NAME\". Make sure the ID token comes from the same Firebase project as the service account used to authenticate this SDK. See https://firebase.google.com/docs/auth/admin/verify-id-tokens for details on how to retrieve an ID token

When setting the Firebase Admin object in NodeJs I tried the following:

const admin = require('firebase-admin');
admin.initializeApp();

as well as

admin.initializeApp({
  credential: admin.credential.cert(serviceAccount),
  databaseURL: "https://PROJECT-ID.firebaseio.com"
});
like image 216
RmR Avatar asked Oct 25 '25 06:10

RmR


1 Answers

Use the X-Apigateway-Api-Userinfo Header

The header's value is the base64 encoded payload of the JWT. There's no need to reverify as API Gateway already verified the token for you and has made the contents available for your use.

Example for Node.js devs:

Buffer.from(req.header("x-apigateway-api-userinfo"), "base64").toString();

If for whatever reason you do need access to the original JWT, it is available in the X-Forwared-Authorization header.


Unnecessary Extra Credit:

To explain the error, the reason you are getting the wrong Audience claim is because the JWT you are trying to verify is a different JWT generated by API Gateway. The original Authorization Header has been replaced with this JWT. Why? It is telling Cloud Functions "Hey Cloud Function, it's me API Gateway that's calling you and here's a signed JWT to prove it". Hence API Gateway's audience ends up being the Cloud Function resource url whereas Firebase's audience is the Project the Firebase sits in.

Just another example of weird inconveniences due to Google's implementation if you ask me; they could have definitely left the Auth header untouched and had API Gateway use a different header, but beggars can't be choosers. 🤷‍♂️


Reference API Gateway Documentation:

Receiving authenticated results in your API

API Gateway usually forwards all headers it receives. However, it overrides the original Authorization header when the backend address is specified by x-google-backend in the API config.

API Gateway will send the authentication result in the X-Apigateway-Api-Userinfo to the backend API. It is recommended to use this header instead of the original Authorization header. This header is base64url encoded and contains the JWT payload.

like image 105
Govind Rai Avatar answered Oct 26 '25 20:10

Govind Rai