'How to configure firebase-admin-sdk for `verifyIdToken` to pass?
I try to use Firebase in my application. The frontend logs the user in using the Web SDK, without any backend. Later, I would like to call some backend APIs. For this reason, I pass the idToken to the backend and try to validate the user as described in the Firebase docs.
When I do the above flow locally using the Firebase Emulator everything works as expected.
When I switch off the Emulator the idToken validation fails with
{
errorInfo: {
code: 'auth/argument-error',
message: 'Firebase ID token has invalid signature. See https://firebase.google.com/docs/auth/admin/verify-id-tokens for details on how to retrieve an ID token.'
},
codePrefix: 'auth'
}
I created a Google hosted Firebase function to check if I can get the idToken validated there. The above setup works when the validation happens within the Google infrastructure.
Based on the above, I think the issue is in my FirebaseApp setup in the API. What that issue might be?
This is my setup.
I define 3 environment variables:
FIREBASE_DB_URL=https://<project-id>.firebaseio.com
FIREBASE_PROJECT_ID=<project-id>
GOOGLE_APPLICATION_CREDENTIALS=/path/to/service-account.json
I checked and cat $GOOGLE_APPLICATION_CREDENTIALS prints the correct file.
I initialize Firebase in the API with
import admin from "firebase-admin";
if(admin.apps.length == 0) {
admin.initializeApp({
credential: admin.credential.applicationDefault(),
databaseURL: process.env.FIREBASE_DB_URL,
projectId: process.env.FIREBASE_PROJECT_ID,
});
console.log('Firebase initialized')
} else {
console.warn('Firebase already initialized')
}
and this is the validating code
import { DecodedIdToken } from 'firebase-admin/lib/auth/token-verifier';
import { getAuth } from 'firebase-admin/auth';
import './initializeFirebase';
export default async function needsLoggedInUser(idToken: string): Promise<DecodedIdToken|false> {
try {
return await getAuth().verifyIdToken(idToken)
} catch(err) {
console.error(err)
return false
}
}
I use the above in a NextJS API code as
import { NextApiRequest, NextApiResponse } from 'next'
import { getDatabase } from 'firebase-admin/database';
import 'services/backend/initializeFirebase';
import needsLoggedInUser from 'services/backend/needsLoggedInUser';
export default async function handler(req: NextApiRequest, res: NextApiResponse) {
// As an admin, the app has access to read and write all data, regardless of Security Rules
const decodedToken = await needsLoggedInUser(req.body.user)
if(!decodedToken) {
return res.status(403).send("403 Forbidden")
}
/// ... rest of the API
}
Sources
This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.
Source: Stack Overflow
| Solution | Source |
|---|
