Firebase Auth ID token has incorrect "aud" claim

14,069

Solution 1

Your problem may be that you are trying to use the JWT token returned by one of the auth() functions like firebaseRef.auth().signInWithPopup(). These do return a JWT token, however the auth claims will likely be wrong and won't pass verification by verifyIdToken. Firebase tech support confirmed this.

You have to use the firebaseRef.auth().currentUser.getToken() function. That token will pass verification.

Solution 2

TLDR: As mentioned in another answer, you are not correctly initializing the App.

Although, I'm a bit late on this, I had the same issue, so I decided to dive in and see what was going on behind the hood.

First off, unless the API has changed since this question was asked, serviceAccount doesn't exist as a property as part of the AppOptions interface, which is probably why you were getting the error. So I'm going to assume what you have there is meant to be in the credential key.

Second, you see that this error is thrown at https://github.com/firebase/firebase-admin-node/blob/master/src/auth/token-verifier.ts (line 187 at the time of this writing) where the aud claim in the token is compared against this.projectId.

Now, as other answers mention, this could be because the token that you are trying to verify was not created client-side, but by some other custom method, in which case the aud claim could be non-existent, something completely random, or something that definitely won't equal your projectId so you should check that first.

However, if you are certain the token was created client-side, then it boils down to projectId not being set, or at least not set in the way you expect. If you look at the getProjectId() method in https://github.com/firebase/firebase-admin-node/blob/master/src/utils/index.ts (line 66 at the time of this writing), you see that the projectId is determined in one of 3 ways: from the app.options object directly, from the projectId property in app.options.credential, OR from process.env.GOOGLE_CLOUD_PROJECT || process.env.GCLOUD_PROJECT. This means that if the projectId is not set and if your project is hosted on GCloud (which I'm assuming stripmall-0000 is), then Google will automagically use your current environment's projectId for anything related to firebase-auth, not the projectId of the originating project.

So, three options:

  1. Initialize your app with projectId set directly in AppOptions:

    firebase.initializeApp({
        databaseURL: <my db url here>,
        // Set your projectId directly here in options:
        projectId: <your-projectId-here>
    });
    
  2. Or probably better to do this way by setting your credentials object properly:

    firebase.initializeApp({
        credentials: admin.credential.cert(<<path-to-your-certificate> || <admin.ServiceAccount object>>),
        databaseURL: <my db url here>
    });
    
  3. Or, just host the app within the same project as your firebase app (now that they are part of the same ecosystem) so that the environment variables are the same. (Not actually 100% about this, but I'm assuming this is how firebase-functions a.k.a. cloud-functions works)

Solution 3

The problem for me was not the token but that I needed to initialize my backend using a service account. Doing that you can also test and debug from the local dev server.

FileInputStream serviceAccount = new FileInputStream("path/to/serviceAccountKey.json");

FirebaseOptions options = new FirebaseOptions.Builder()
            .setCredentials(GoogleCredentials.fromStream(serviceAccount))
            .setDatabaseUrl("https://<DATABASE_NAME>.firebaseio.com/")
            .build();

FirebaseApp.initializeApp(options);
FirebaseAuth firebaseAuth = FirebaseAuth.getInstance();

// Get the FB uid from the token
FirebaseToken decodedToken = firebaseAuth.verifyIdTokenAsync(token).get();
String uid = decodedToken.getUid();

source: https://firebase.google.com/docs/admin/setup

Solution 4

As Thach Lockevn mentioned in the comments The solution that worked for me was:

import { AngularFireAuth } from '@angular/fire/auth';
import { auth } from 'firebase/app';

this.angularFireAuth.signInWithPopup(new auth.GoogleAuthProvider()).then((googleAuth) => {
        this.user = googleAuth.user;
        googleAuth.user.getIdToken().then(tkn => {
            this.token = tkn;
            //send the token to the backend...
        });
    });
Share:
14,069
Faustus
Author by

Faustus

Updated on June 04, 2022

Comments

  • Faustus
    Faustus almost 2 years

    I'm trying to verify an idToken backend. The user has successfully logged in to firebase client side but when I try to verify the idToken on my backend I get this not very helpful error message

    Firebase Auth ID token has incorrect "aud" claim

    The error message seems to have become a little more informative, and boils down to not having the project name in the auth key:

    Error: Firebase ID token has incorrect "aud" (audience) claim. Expected "stripmall-0000" but got "617699194096-0aafcvsml0gke61d6077kkark051f3e1.apps.googleusercontent.com". 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/server/verify-id-tokens for details on how to retrieve an ID token.

    Anyone with the slightest idea what could be wrong? I receive the tokenId correctly from the client so that shouldn't be a problem. Sincere appologies if this has been asked before or is trivial in any other way.

      firebase.initializeApp({
            serviceAccount: {
                "type": "service_account",
                "project_id": <project id here>,
                "private_key_id": <key id goes here>,
                "private_key": <key goes here>
                "client_email": <email goes here>,
                "client_id": <my client id>,
                "auth_uri": "https://accounts.google.com/o/oauth2/auth",
                "token_uri": "https://accounts.google.com/o/oauth2/token",
                "auth_provider_x509_cert_url": "https://www.googleapis.com/oauth2/v1/certs",
                "client_x509_cert_url": <url goes here>
            },
            databaseURL: <my db url here>
        });
    
        router.post("/verify", function (req, res) {
            firebase.auth().verifyIdToken(req.body.idToken).then(function (decodedToken) {
                var uid = decodedToken.sub;
                res.send(uid);
            }).catch(function (error, param2) {
                console.log(error);  // 'Firebase Auth ID token has incorrect "aud" claim'
            });
    
        });
    
  • Glen Swift
    Glen Swift almost 7 years
    works for me, this should be accepted as correct answer
  • Akshita Kanojia
    Akshita Kanojia about 6 years
    I confirm this works, I've just encountered this issue in 2018. Use user.getIdToken() solve the problem.
  • Liau Jian Jie
    Liau Jian Jie about 5 years
    Did their tech support explain why this was the case?
  • Govind Rai
    Govind Rai over 4 years
    This solved my problem. I am using one service account to manipulate multiple firebases from different projects. Without passing the projectId explicitly it would just try to write to the project which the service account was created in.
  • Saumil Shah
    Saumil Shah almost 4 years
    For anyone running into this issue, actually the correct one to use is firebase.auth().currentUser.getIdToken()
  • try_catch
    try_catch about 3 years
    If the tokens coming out from firebase.auth().onIdTokenChanged(async (user) => { if (user) { const token = await user.getIdToken(); doesn't work, how am I supposed to use firebase.auth().currentUser.getToken() for server-side authentication such as NextJS?