QUESTION:
I’m creating an app with React Native and Node.js. I already have my auth system. Now I try to implement Google Sign-In. So far, I’ve:
- Created a Google application in Firebase.
- Generated the
.keystore
file and obtained the SHA1 key. - Updated the
build.gradle
to install the SDK on the client. - Placed the file in the client and the Google service file in my Node.js app.
- Implemented the code in React Native and Node.js.
- Retrieved the token from the client.
However, I encountered an error while testing with Postman. The error message is:
“Firebase ID token has incorrect ‘aud’ (audience) claim. Expected ‘tak-muscu’ but got ‘XXXX-ruib6t1s7lochabens3f3ep67pa411nc.apps.googleusercontent.com’. Make sure the ID token comes from the same Firebase project as the service account used to authenticate this SDK. See Firebase documentation for details on how to retrieve an ID token.”
Here is my code:
React Native (Client Side):
import { GoogleSignin } from '@react-native-google-signin/google-signin'; GoogleSignin.configure({ webClientId: 'XXXXX-ruib6t1s7lochabens3f3ep67pa411nc.apps.googleusercontent.com', androidClientId: 'XXXXX-fvv7nndd0q53hvoht9cldt82jm5a9306.apps.googleusercontent.com', scopes: ['profile', 'email'], }); const signIn = async () => { try { await GoogleSignin.hasPlayServices(); const userInfo = await GoogleSignin.signIn(); const idToken = userInfo.idToken; console.log('ID Token:', idToken); } catch (error) { console.error('Google Sign-In error', error.message); } };
Express Route (Server Side):
const express = require('express'); const router = express.Router(); const { verifyGoogleToken } = require('./verifyGoogleToken'); router.post('/google-signin', async (req, res) => { const { idToken } = req.body; const result = await verifyGoogleToken(idToken); if (result.status === 'success') { res.send({ message: 'Authentication successful', user: result.decodedToken }); } else { res.status(401).send({ message: 'Authentication failed', error: result.message }); } }); module.exports = router;
Verify Google Token Function:
const admin = require('firebase-admin'); const verifyGoogleToken = async (idToken) => { try { const decodedToken = await admin.auth().verifyIdToken(idToken); console.log("Token validated successfully", decodedToken); return { status: 'success', uid: decodedToken.uid }; } catch (error) { console.error('Error verifying token', error); return { status: 'error', message: error.message }; } }; module.exports = { verifyGoogleToken };
App.js Server Initialization:
const admin = require('firebase-admin'); const serviceAccount = require('./secrets/service-account-file.json'); admin.initializeApp({ credential: admin.credential.cert(serviceAccount), });
I tried it 4 times and I get the same error every time. How can I resolve this issue?
ANSWER:
Understanding the Error
The error message you are encountering, “Firebase ID token has incorrect ‘aud’ (audience) claim,” indicates that the ID token’s audience claim does not match the expected value. This usually happens when the token is generated using a different Firebase project than the one your server is using to verify the token.
Steps to Resolve the Issue
Step 1: Verify Firebase Project Configuration
Ensure that the Firebase project used to generate the ID token in your React Native app is the same as the one used in your Node.js backend for verification.
- Firebase Console: Go to the Firebase console and open the project you are working on.
- Project Settings: Navigate to Project Settings and verify the
project_id
,webClientId
, andandroidClientId
. - Service Account: Ensure that the service account file used in your Node.js app belongs to the same Firebase project.
Step 2: Update Firebase Configuration in React Native
Make sure that the webClientId
and androidClientId
in your GoogleSignin.configure
method match the client IDs listed in your Firebase project settings.
React Native (Client Side):
import { GoogleSignin } from '@react-native-google-signin/google-signin'; GoogleSignin.configure({ webClientId: 'YOUR_CORRECT_WEB_CLIENT_ID.apps.googleusercontent.com', androidClientId: 'YOUR_CORRECT_ANDROID_CLIENT_ID.apps.googleusercontent.com', scopes: ['profile', 'email'], }); const signIn = async () => { try { await GoogleSignin.hasPlayServices(); const userInfo = await GoogleSignin.signIn(); const idToken = userInfo.idToken; console.log('ID Token:', idToken); } catch (error) { console.error('Google Sign-In error', error.message); } };
Step 3: Verify Token on the Server
Ensure your server is correctly set up to verify the ID token using the Firebase Admin SDK.
Express Route (Server Side):
const express = require('express'); const router = express.Router(); const { verifyGoogleToken } = require('./verifyGoogleToken'); router.post('/google-signin', async (req, res) => { const { idToken } = req.body; const result = await verifyGoogleToken(idToken); if (result.status === 'success') { res.send({ message: 'Authentication successful', user: result.decodedToken }); } else { res.status(401).send({ message: 'Authentication failed', error: result.message }); } }); module.exports = router;
Verify Google Token Function:
const admin = require('firebase-admin'); const verifyGoogleToken = async (idToken) => { try { const decodedToken = await admin.auth().verifyIdToken(idToken); console.log("Token validated successfully", decodedToken); return { status: 'success', decodedToken }; } catch (error) { console.error('Error verifying token', error); return { status: 'error', message: error.message }; } }; module.exports = { verifyGoogleToken };
Step 4: Ensure Consistent Environment Setup
- Check Environment Variables: Ensure your environment variables and configurations are consistent across your development and production environments.
- SHA1 Key: Make sure the SHA1 key used in the Firebase project settings matches the one used to generate the
.keystore
file.
Example Code for Correct Setup
Here is an example of the correct setup for your React Native app and Node.js backend:
React Native (Client Side):
import { GoogleSignin } from '@react-native-google-signin/google-signin'; GoogleSignin.configure({ webClientId: 'YOUR_CORRECT_WEB_CLIENT_ID.apps.googleusercontent.com', androidClientId: 'YOUR_CORRECT_ANDROID_CLIENT_ID.apps.googleusercontent.com', scopes: ['profile', 'email'], }); const signIn = async () => { try { await GoogleSignin.hasPlayServices(); const userInfo = await GoogleSignin.signIn(); const idToken = userInfo.idToken; console.log('ID Token:', idToken); } catch (error) { console.error('Google Sign-In error', error.message); } };
Express Route (Server Side):
const express = require('express'); const router = express.Router(); const { verifyGoogleToken } = require('./verifyGoogleToken'); router.post('/google-signin', async (req, res) => { const { idToken } = req.body; const result = await verifyGoogleToken(idToken); if (result.status === 'success') { res.send({ message: 'Authentication successful', user: result.decodedToken }); } else { res.status(401).send({ message: 'Authentication failed', error: result.message }); } }); module.exports = router;
Verify Google Token Function:
const admin = require('firebase-admin'); const verifyGoogleToken = async (idToken) => { try { const decodedToken = await admin.auth().verifyIdToken(idToken); console.log("Token validated successfully", decodedToken); return { status: 'success', decodedToken }; } catch (error) { console.error('Error verifying token', error); return { status: 'error', message: error.message }; } }; module.exports = { verifyGoogleToken };
App.js Server Initialization:
const admin = require('firebase-admin'); const serviceAccount = require('./secrets/service-account-file.json'); admin.initializeApp({ credential: admin.credential.cert(serviceAccount), });
Additional Resources
For further reading and troubleshooting, refer to the following resources: