I’m running into a strange error:
I was writing the firestore rules for my database and I realized that my BE (in node, deployed on Google’s cloud run) stopped working due to access denied problems. This seems very strange to me, from all my assessments the login from BE and therefore with SDK users should not validate these rules. Also by setting the rules completely open, the API start again working. At this point I fear that the problem is how I set up the authentication for the server-side service account… so I ask you for your point of view
firebase config
import { getAuth } from "firebase/auth";
import { initializeApp } from "firebase/app";
import { getFirestore } from "firebase/firestore/lite";
import stripe from "stripe";
import dotenv from "dotenv";
dotenv.config();
// Firebase configuration object containing API keys and other credentials
const firebaseConfig = {
apiKey: process.env.API_KEY, // API key for accessing Firebase services
authDomain: process.env.AUTH_DOMAIN, // Domain for authentication
projectId: process.env.PROJECT_ID, // ID of the Firebase project
storageBucket: process.env.STORAGE_BUCKET, // Storage bucket for Firebase storage
messagingSenderId: process.env.MESSAGING_SENDER_ID, // Sender ID for Firebase Cloud Messaging
appId: process.env.APP_ID, // ID of the Firebase application
};
// Initialize Firebase app with the provided configuration
const app = initializeApp(firebaseConfig);
// Get the authentication instance from the Firebase app
export const auth = getAuth(app);
// Get the Firestore database instance from the Firebase app
export const db = getFirestore(app);
// Initialize Stripe with the private key from the environment variables
export const STRIPE = new stripe(process.env.STRIPE_PRIVATE_KEY);
service account
import admin from "firebase-admin";
// Defining service account configuration object using environment variables
const SERVICE_ACCOUNT = {
type: process.env.SERVICE_ACCOUNT,
project_id: process.env.PROJECT_ID,
private_key_id: process.env.PRIVATE_KEY_ID,
private_key: process.env.PRIVATE_KEY.replace(/\n/g, "n"), // Replacing escaped newline characters
client_email: process.env.CLIENT_EMAIL,
client_id: process.env.CLIENT_ID,
auth_uri: process.env.AUTH_URI,
token_uri: process.env.TOKEN_URI,
auth_provider_x509_cert_url: process.env.AUTH_PROVIDER,
client_x509_cert_url: process.env.CLIENT_CERT_URL,
universe_domain: process.env.UNIVERSE_DOMAIN,
};
// Initializing Firebase Admin SDK with service account credentials
export default admin.initializeApp({
credential: admin.credential.cert(SERVICE_ACCOUNT),
serviceAccountId: process.env.CLIENT_EMAIL,
});
One example API
import {
or,
and,
doc,
query,
where,
getDoc,
getDocs,
deleteDoc,
updateDoc,
collection,
} from "firebase/firestore/lite";
import {
generateToken,
createResponse,
createCustomToken,
sendErrorResponse,
returnErrorResponse,
decryptPasswordFunction,
} from "../../utils/utils.js";
import {
SUCCESS,
EVENT_EXPIRED,
OTP_INCORRECT,
LOG_IN_SUCCESS,
USER_NOT_FOUND,
NOT_AUTHORISED,
OTP_TIME_EXPIRED,
EVENT_NOT_EXISTS,
EVENT_NOT_ACTIVE,
PASSWORD_MISMATCH,
UNAUTHENTICATED_USER,
EMAIL_OR_PHONE_NUMBER_REQUIRED,
NOT_REGISTER_WITH_EMAIL_PASSWORD,
USER_NOT_ACTIVE,
} from "../../constants/responseConstants.js";
import {
SUCCESS_CODE,
VALIDATION_ERROR_CODE,
BAD_REQUEST_ERROR_CODE,
} from "../../constants/statusConstants.js";
import moment from "moment";
import admin from "../../constants/serviceAccount.js";
import { db } from "../../constants/fireBaseConfig.js";
import { JWT, USER_ROLE, COLLECTION } from "../../constants/constant.js";
import { loginValidator, languageValidator } from "../../shared/validator.js";
//Login function appears to handle user authentication
export const login = async (request, response) => {
console.info("Starting execution of the login function ", request);
// Define Firestore collections
const USERS = collection(db, COLLECTION.USER);
const OTPS = collection(db, COLLECTION.OTP);
const EVENTS = collection(db, COLLECTION.EVENT);
const APP_INFOS = collection(db, COLLECTION.AAP_INFO);
try {
const { body } = request;
// Validate request language
let languageValue = languageValidator().validate(request.query);
const { respose_language } = languageValue.value;
// Validate request body data
const VALIDATE_DATA = loginValidator().validate(body);
const { error, value } = VALIDATE_DATA;
// Return validation error response if validation fails
if (error)
return await sendErrorResponse(
response,
VALIDATION_ERROR_CODE,
error.details[0].message,
respose_language
);
// Destructure validated values
const { password, phone_number, otp, email } = value;
// Check for required fields
if (
(body?.email && body?.phone_number) ||
(!body?.email && !body?.phone_number)
)
return await sendErrorResponse(
response,
BAD_REQUEST_ERROR_CODE,
EMAIL_OR_PHONE_NUMBER_REQUIRED,
respose_language
);
let userQuery, userSnapShot,eventData;
// Handle email case
if (email) {
userQuery = query(USERS, where("email", "==", email));
userSnapShot = await getDocs(userQuery);
}
Error
@firebase/firestore: Firestore (10.11.1_lite): RestConnection RPC 'RunQuery' 0x88991bb1 failed with error: [FirebaseError: Request failed with error: Missing or insufficient permissions.] {
code: 'permission-denied',
customData: undefined,
toString: [Function (anonymous)]
} url: https://firestore.googleapis.com/v1/projects/app-power-bank/databases/(default)/documents:runQuery request: {
structuredQuery: {
from: [ { collectionId: 'users' } ],
where: {
fieldFilter: {
field: { fieldPath: 'email' },
op: 'EQUAL',
value: { stringValue: '[email protected]' }
}
},
orderBy: [ { field: { fieldPath: '__name__' }, direction: 'ASCENDING' } ]
}
}
Error occured in login function: [FirebaseError: Request failed with error: Missing or insufficient permissions.] {
code: 'permission-denied',
customData: undefined,
toString: [Function (anonymous)]
}
Give me your point of view..