What is Firebase App Check and how do create and verify tokens to secure backend APIs for iOS, Android, and Web?
Firebase App Check is a feature introduced by Firebase to provide an extra security layer for the Firebase resources. Along with the Firebase resources, we can secure our backend i.e. non-firebase resources from the unauthorized request. Thus Firebase App check also helps in reducing our billing.
Let’s assume we have our backend APIs and we want to protect our backend resources so that the API resources can’t be used by unauthorized users.
For this, we need to install the Firebase Admin Package firebase-admin
and afterwards, we’ll import that package and initialize it.
I'm creating backend API in the Nodejs and with the Express Framework. Firebase has also provided their documentation for the custom backend resources, please visit the below links for the documentation
Firebase App Check https://firebase.google.com/docs/app-check
Send Firebase APP Check token from web https://firebase.google.com/docs/app-check/web/custom-resource
Verify Firebase APP Check Security token for Custom Backend Resource https://firebase.google.com/docs/app-check/custom-resource-backend
Go to the Project Overview → Service Accounts → Then Generate Private key, it will download the JSON file in the system. Please keep the JSON file private i.e. we need to keep the JSON file on the server side only.
Initializing the firebase admin sdk with the json account
//Import Package
const app = require("firebase-admin/app");
const { getAppCheck } = require("firebase-admin/app-check");
//Import configuration
const configuration = require("our-configuration-file");
//Initializating firebase using json configuration
const firebaseApp = app.initializeApp({
credential: app.cert(configuration.firebase.adminServiceAccount),
databaseURL: configuration.firebase.databaseURL
});
After initializing the Firebase app, now we can add the appCheckVerification
token function and export it so we can use the same middleware function from the other routes file where we need to secure the rest APIs.
const appCheckVerification = async (req, res, next) => {
const appCheckToken = req.header("X-Firebase-AppCheck");
if (!appCheckToken) {
res.status(401);
return next("Unauthorized");
}
try {
const appCheckClaims = await getAppCheck().verifyToken(appCheckToken);
//verify token succeeds we can now navigate to other middleware or next step
// in the route file
return next();
} catch (err) {
res.status(401);
return next("Unauthorized");
}
}
The Token will be created from the client side whether it's web, Android, or iOS. In the backend, we only verify the token.
Let’s combine all the code to see how our final code looks like
//firebase service file
//Import Package
const app = require("firebase-admin/app");
const { getAppCheck } = require("firebase-admin/app-check");
//Import configuration
const configuration = require("our-configuration-file");
//Initializating firebase using json configuration
const firebaseApp = app.initializeApp({
credential: app.cert(configuration.firebase.adminServiceAccount),
databaseURL: configuration.firebase.databaseURL
});
const appCheckVerification = async (req, res, next) => {
const appCheckToken = req.header("X-Firebase-AppCheck");
if (!appCheckToken) {
res.status(401);
return next("Unauthorized");
}
try {
const appCheckClaims = await getAppCheck().verifyToken(appCheckToken);
//verify token succeeds we can now navigate to other middleware or next step
// in the route file
return next();
} catch (err) {
res.status(401);
return next("Unauthorized");
}
}
module.exports = {
appCheckVerification
}
Now we can use that function in the route file
//Route file
const ourRouter = require("express").Router();
const firebase = require("services/firebase"); //assuming we created that file inside services folder
//Route File
ourRouter
.route("/our-route-url")
.get(
[firebase.appCheckVerification],
function (req, res) {
//do our own stuff after token verified
}
);
If we want to check whether it's working fine, we need an App Check Token and that token we can also create in the backend for that we need an app ID. We can get the app ID under the General Tab in the project settings.
If we don’t create any app, please create the app and go to that app there we can see the App ID label and its value.
const appId = "my app id";
//Creating APP Check Token
const data = await getAppCheck().createToken(appId);
//JSON data - token and ttlMillis are the keys
{
token: "our jwt token",
ttlMillis: 3600000
}
/* ***
Default ttlMillis is 3600000 means 1 hour, we can create token with
Minimum 30 minutes
Maximum 7 days
*** */
We’ll send the APP Check TOken in the headers with X-Firebase-AppCheck
the key. If in the backend all APIs are secured with an app check token then it's better to send that parameter using the HTTP interceptor and if it's not that case then we can only in the particular API.
If still any doubt, please mention it in the comments.
🔐 Stay Safe on the Web with the Firebase APP Check 😎