Search code examples
javascriptgoogle-cloud-firestorefirebase-authenticationfirebase-security

Permission Denied in Firestore


I did not use the emulator. I don't think I have enough experience for that.

Here is my rule:

match /pilots/{userId}{
     allow read: if request.auth != null;
      allow write: if true;
    }

I also tried:

match /pilots/{userId}{
        allow read: if request.auth.uid == userId;
      allow write: if true;
    }

Neither of them worked.

Here is the query on the backend that fails:

app.get("/banner/:pilotid", async function (req,res){
    let pilotid = req.params.pilotid
    let bannerresponse = await getBannerData(pilotid)

    res.set({
        "Content-Type": "application/json",
    });
    res.send(bannerresponse);
});

Specifically this line

async function getBannerData(pilotid){
    let pilot = await db.collection('pilots').doc(pilotid).get()

The userid variable comes from the auth login frontend and passed to the backend. That value appears fine when console logged. I am using express for my listener on the backend.

Here is the frontend code:

auth.onAuthStateChanged(async function(user){
    if (user){
        //user is signed in
        const userid = user.uid;
        await populateBanner(userid)
        
    }
    else{
        //not signed in
        window.location.href = "./index.html"
    }
})


async function populateBanner(userid){
    var data = await fetch(bannerendpoint + userid, {
        method: "GET",
        headers: {
            'Content-Type': 'application/json'
        }
    });

Here is the firebase call on the frontend.

I also tried version 8.10.0 and it didn't work either. Version 9.0.2 wouldn't let me login.

My collection is a of a few fields with the record I'd copy and pasted from the user table in Firebase Auth users list.

My app is in JavaScript.

Here is the full error message:

(node:12620) UnhandledPromiseRejectionWarning: FirebaseError: Missing or insufficient permissions. at new FirestoreError (C:\Users\leinh\Documents\Development\FlyTheWorld\node_modules@firebase\firestore\dist\node-cjs\database-b718dabb-791d92fb.js:377:28) at fromRpcStatus (C:\Users\leinh\Documents\Development\FlyTheWorld\node_modules@firebase\firestore\dist\node-cjs\database-b718dabb-791d92fb.js:7142:12)
at fromWatchChange (C:\Users\leinh\Documents\Development\FlyTheWorld\node_modules@firebase\firestore\dist\node-cjs\database-b718dabb-791d92fb.js:7357:35)
at PersistentListenStream.onMessage (C:\Users\leinh\Documents\Development\FlyTheWorld\node_modules@firebase\firestore\dist\node-cjs\database-b718dabb-791d92fb.js:15313:27) at C:\Users\leinh\Documents\Development\FlyTheWorld\node_modules@firebase\firestore\dist\node-cjs\database-b718dabb-791d92fb.js:15246:30 at C:\Users\leinh\Documents\Development\FlyTheWorld\node_modules@firebase\firestore\dist\node-cjs\database-b718dabb-791d92fb.js:15282:28 at C:\Users\leinh\Documents\Development\FlyTheWorld\node_modules@firebase\firestore\dist\node-cjs\database-b718dabb-791d92fb.js:21930:13 at C:\Users\leinh\Documents\Development\FlyTheWorld\node_modules@firebase\firestore\dist\node-cjs\database-b718dabb-791d92fb.js:21996:20 at processTicksAndRejections (internal/process/task_queues.js:95:5) (Use node --trace-warnings ... to show where the warning was created) (node:12620) UnhandledPromiseRejectionWarning: Unhandled promise rejection. This error originated either by throwing inside of an async function without a catch block, or by rejecting a promise which was not handled with .catch(). To terminate the node process on unhandled promise rejection, use the CLI flag --unhandled-rejections=strict (see https://nodejs.org/api/cli.html#cli_unhandled_rejections_mode). (rejection id: 1) (node:12620) [DEP0018] DeprecationWarning: Unhandled promise rejections are deprecated. In the future, promise rejections that are not handled will terminate the Node.js process with a non-zero exit code.

Thanks for the help. Let me know if you need more information.


Solution

  • You're signing the user in in your front-end code, but not in your backend code. That means that your db.collection('pilots').doc(pilotid).get() runs without an authenticated user, which explains the error you get.

    You have a few options (in descending order of preference):

    1. Read the data directly from the client, instead of relegating that to the server. In that scenario the client-side Firestore SDK will pass the authenticated user to the database.

    2. Use the Node.js Admin SDK in your server-side code, which has administrative access to the database. This means the server-side code will bypass all security rules, so you will have to ensure the user is authorized in your server-side application code.

    3. Sign in the same user in your server-side code. I typically wouldn't recommend this, but it may be an option.