Based on what is written here, they are "impersonating a user" with a new Firebase admin app instance, so that when they do a write/read the security rules will be triggered for that user.
https://firebase.google.com/docs/database/extend-with-functions
I'm trying to do the same thing but for Firestore, but it doesn't seem to work.
Goal
I have reading/writing to firestore go through an express backend hosted as cloud function. I do not want to implement manual security rules in that backend.
I want to have the firebase-admin app instance to behave "as a user" so the firestore security rules are triggered appropriately, and I can unify my security in the security rules.
Here is the code I'm using:
1. get the admin app options
export function getLocalAdminAppOptions(): admin.AppOptions {
// we are running locally
const serviceAccount: admin.ServiceAccount = {
clientEmail: CLIENT_EMAIL,
projectId: PROJECT_ID,
privateKey: (PRIVATE_KEY || "").replace(/\\n/g, "\n")
}
return {
credential: admin.credential.cert(serviceAccount),
databaseURL: DATABASE_URL
}
}
2. add the impersonation options & instantiate admin app
import * as Admin from "firebase-admin"
import * as Functions from "firebase-functions"
const appOptions = getLocalAdminAppOptions()
const token: Admin.auth.DecodedIdToken = await Admin.auth().verifyIdToken(req.idToken)
const authOverwrite: Functions.EventContext["auth"] = {
token,
uid: req.authUser.uid
}
appOptions.databaseAuthVariableOverride = authOverwrite
const uniqueAppName = "adminAppAsUser:" + req.authUser.uid
const adminAppAsUser = Admin.initializeApp(appOptions, uniqueAppName)
3. make a firestore call with the impersonation app instance
const snap = await adminAppAsUser
.firestore()
.collection(`test`)
.doc("test")
.get()
return snap.data()
The Problem:
The adminAppAsUser seems to still be a admin app with full access rights, ignoring the security rules.
Bad workaround
I did manage to find a "hacky" workaround: Create a new instance of Firebase for the web inside my backend, and signing with custom token, and use that to access firestore.
Problems with this workaround: signInWithCustomToken takes 800ms every time I run the cloud function!
Code for the workaround:
const uniqueAppName = "adminAppAsUser:" + req.authUser.uid
const adminAppAsUser = Firebase.initializeApp(configs.dev, uniqueAppName)
const token = await Admin.auth().createCustomToken(req.authUser.uid)
await adminAppAsUser.auth().signInWithCustomToken(token)