Skip to content

The function createUserWithEmailAndPassword doesn't grant the necessary permissions to access Firestore. #5794

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Closed
ThomasGysemans opened this issue Dec 5, 2021 · 7 comments

Comments

@ThomasGysemans
Copy link

My environment

  • Operating System: Windows 10 21H1
  • Browser: Brave
  • Firebase SDK version: ^9.5.0 in nextjs config
  • Firebase Product: auth, firestore

The problem

NOTE: I'm using NEXTJS

NOTE: I'm reporting this issue because it looks like a bug, see StackOverflow for more details.

My goal: I want to add a new document in a collection entitled "users" in Firestore when a user creates an account with email and password. Therefore, I use createUserWithEmailAndPassword. Here is an example:

import { useState } from "react";
import {
  createUserWithEmailAndPassword,
  getAuth,
} from "firebase/auth";
import {
  collection,
  getFirestore,
  addDoc,
} from "firebase/firestore";

export const ConnectionPage = () => {
  // the values of the inputs in the HTML content
  const [email, setEmail] = useState("");
  const [password, setPassword] = useState("");

  // the function executed when the user clicks the register button
  const submit = async (e) => {
    e.preventDefault();
    // create a new user with email and password
    // and add the document in the "users" collection
    try {
      const userCredentials = await createUserWithEmailAndPassword(
        getAuth(),
        email,
        password
      );
      const user = userCredentials.user;
      const userInfo = {
        uid: user.uid,
        // ...and all kind of data
      };
      // my problem starts here
      // the following lines will throw an error
      // "[code=permission-denied]: Missing or insufficient permissions."
      // whereas, according to the rules in Firestore, it should work
      // because I just ask the user to be authenticated (`allow read, write: if request.auth != null`)
      // and according to the documentation, `createUserWithEmailAndPassword` logs in the user.
      const collectionRef = collection(getFirestore(), "users");
      const docRef = await addDoc(collectionRef, userInfo);
      // my dream is to reach this line ;(
      console.log(`New document with id '${docRef.id}' created successfully.`);
    } catch (e) {
      console.error("An error has occured during register, look:");
      console.error(e.toString());
    }
  };

  // returns a form
  // with an email input
  // and a password input
  // and a button to register
};

Here are my rules in Firestore:

rules_version = '2';
service cloud.firestore {
  match /databases/{database}/documents {
    match /{document=**} {
      allow read, write: if request.auth != null;
    }
  }
}

I tried:

  • in-promise syntax (.then()) but the problem is the same than with async/await
  • onAuthStateChanged(), but the same problem occurs.
  • Changing the rules to something more complex (like testing the existence of the user according to the request.auth.uid), it doesn't work either.

This is the first time I report an issue, so I hope I added all the necessary details.

@dconeybe
Copy link
Contributor

dconeybe commented Dec 6, 2021

Hi @CodoPixel I'll take a look at this. I don't see anything immediately obvious that you are doing wrong. I have a few questions though.

  1. What happens if you change your security rules to "allow all"?
  2. What happens if you use the Firestore emulator?
  3. Please reproduce with debug logging enabled and post the resulting logs. Enable debug logging both at the Firebase level and at the Firestore level.

@ThomasGysemans
Copy link
Author

First of all, thank you for your answer.

NOTE: I have changed the code to:

// ConnectionPage.js
// same as the first, but the submit function is now the following
const submit = async (e) => {
    e.preventDefault();
    try {
        const userCredentials = await createUserWithEmailAndPassword(
          getAuth(),
          email,
          password
        );
    } catch (e) {
        console.error(e.toString());
    }
}

And I'm using a context to transfer the state of the auth to my entire app

// auth.js
import { createContext, useEffect, useContext } from "react";
import { doc, getFirestore, getDoc, setDoc } from "firebase/firestore";
import { auth } from "./firebase";

const AuthContext = createContext({});

export const AuthProvider = ({ children }) => {
  useEffect(() => {
    return auth.onAuthStateChanged(async (user) => {
      if (!user) {
        console.log("no user!");
        return;
      }
      const token = await user.getIdToken();
      // console.log("token", token);
      // console.log("user", user);
      // console.log("Trying to access firestore...");
      const docRef = doc(getFirestore(), "users", user.uid);
      const docSnapshot = await getDoc(docRef);
      // I have never reached the following lines
      if (docSnapshot.exists()) {
        // the user had already an account
        // so we can just modify a few fields
        console.log("user already exists");
      } else {
        // the user didn't have an account,
        // so we must add the document
        console.log("user doesn't exist\nCreation of the document...");
        const userInfo = {
          uid: user.uid,
          // etc.
        };
        // await docRef.set(userInfo);
        await setDoc(docRef, userInfo)
          .then(() => {
            console.log(
              `The document with id ${user.uid} has been created successfully.`
            );
          })
          .catch((error) => {
            console.error("error", error.toString());
          });
      }
    });
  }, []);

  return <AuthContext.Provider value={{}}>{children}</AuthContext.Provider>;
};

export const useAuth = () => useContext(AuthContext);

As requested, I have changed the rules to:

rules_version = '2';
service cloud.firestore {
  match /databases/{database}/documents {
    match /{document=**} {
      allow read, write: if true;
    }
  }
}

but I still have the same Runtime Error:

FirebaseError: Missing or insufficient permissions.

Now, about your other questions. I don't know how to use the Firestore emulator yet, so I'll need time to read the whole documentation, outside of my working hours. I will keep you posted.

You also asked me to use setLogLevel(). I don't exactly know how to implement it (because I have never used it), hope it's clear:

// firebase.js
import { setLogLevel } from "firebase/app"

setLogLevel("debug")

const firebaseConfig = {}

const app = initializeApp(firebaseConfig)
// etc.

which returns me (in the console) the following outputs:

[2021-12-06T19:48:29.441Z]  @firebase/firestore: Firestore (9.5.0): FirebaseCredentialsProvider Auth detected
index.esm2017.js?2d33:78 [2021-12-06T19:48:29.447Z]  @firebase/firestore: Firestore (9.5.0): FirestoreClient Received user= gYYsdl24vQe3nHZRk752zV4FVsH3
index.esm2017.js?2d33:78 [2021-12-06T19:48:29.448Z]  @firebase/firestore: Firestore (9.5.0): FirestoreClient Using default OnlineComponentProvider
index.esm2017.js?2d33:78 [2021-12-06T19:48:29.449Z]  @firebase/firestore: Firestore (9.5.0): FirestoreClient Using default OfflineComponentProvider
index.esm2017.js?2d33:78 [2021-12-06T19:48:29.450Z]  @firebase/firestore: Firestore (9.5.0): FirestoreClient Initializing OfflineComponentProvider
index.esm2017.js?2d33:78 [2021-12-06T19:48:29.453Z]  @firebase/firestore: Firestore (9.5.0): FirestoreClient Initializing OnlineComponentProvider
index.esm2017.js?2d33:78 [2021-12-06T19:48:29.457Z]  @firebase/firestore: Firestore (9.5.0): MemoryPersistence Starting transaction: Allocate target
index.esm2017.js?2d33:78 [2021-12-06T19:48:29.460Z]  @firebase/firestore: Firestore (9.5.0): MemoryPersistence Starting transaction: Execute query
index.esm2017.js?2d33:78 [2021-12-06T19:48:29.463Z]  @firebase/firestore: Firestore (9.5.0): QueryEngine Using full collection scan to execute query: Query(target=Target(users/gYYsdl24vQe3nHZRk752zV4FVsH3, orderBy: [__name__ (asc)]); limitType=F)
index.esm2017.js?2d33:78 [2021-12-06T19:48:29.470Z]  @firebase/firestore: Firestore (9.5.0): Connection Creating WebChannel: https://firestore.googleapis.com/google.firestore.v1.Firestore/Listen/channel {"httpSessionIdParam":"gsessionid","initMessageHeaders":{"X-Goog-Api-Client":"gl-js/ fire/9.5.0","Content-Type":"text/plain","X-Firebase-GMPID":"1:647468793659:web:cc48e6001fb7ae4c92011e","Authorization":"Bearer eyJhbGciOiJSUzI1NiIsImtpZCI6IjQ3OTg5ZTU4ZWU1ODM4OTgzZDhhNDQwNWRlOTVkYTllZTZmNWVlYjgiLCJ0eXAiOiJKV1QifQ.eyJpc3MiOiJodHRwczovL3NlY3VyZXRva2VuLmdvb2dsZS5jb20vbmV4dC1zY2llbmNlc2t5IiwiYXVkIjoibmV4dC1zY2llbmNlc2t5IiwiYXV0aF90aW1lIjoxNjM4ODIwMTA5LCJ1c2VyX2lkIjoiZ1lZc2RsMjR2UWUzbkhaUms3NTJ6VjRGVnNIMyIsInN1YiI6ImdZWXNkbDI0dlFlM25IWlJrNzUyelY0RlZzSDMiLCJpYXQiOjE2Mzg4MjAxMDksImV4cCI6MTYzODgyMzcwOSwiZW1haWwiOiJneXNlbWFuc3Rob21hc0BnbWFpbC5jb20iLCJlbWFpbF92ZXJpZmllZCI6ZmFsc2UsImZpcmViYXNlIjp7ImlkZW50aXRpZXMiOnsiZW1haWwiOlsiZ3lzZW1hbnN0aG9tYXNAZ21haWwuY29tIl19LCJzaWduX2luX3Byb3ZpZGVyIjoicGFzc3dvcmQifX0.FmInqc-FVRkhG6v9QSVS4UWpgvZ9DlJEdMrYt6Qi6k2QSiGzxItTiyTIEleKMZGdXWTGGPu_o3Tqpe0o9mVz70yUge6NTXkUnVr7Oa6cgzdGZ0dJs9VSyPnThMwcS3hyufnPy-vpXfscScyH63I9xi6i-RqVpHRaWCx77yNcZXJdW-uN0F0P7lwrh0Ykx6DEJBJ9gbTd1KnLvsaVVrVD1MLUVQD30FUg8Vq7hmtcVP0j0ZcmDVvnLeGNJ1igZXD2Ny8nDGgbeUdqWhPIUEepIHndDtLDFtjRcNyPNVdgLrtSwLX49ivtLExLZ6v7ItW8uTdTRliFz_4nFuyP8fLndg"},"messageUrlParams":{"database":"projects/next-sciencesky/databases/(default)"},"sendRawJson":true,"supportsCrossDomainXhr":true,"internalChannelParams":{"forwardChannelRequestTimeoutMs":600000},"forceLongPolling":false,"detectBufferingProxy":false,"xmlHttpFactory":{"l":null,"j":false},"httpHeadersOverwriteParam":"$httpHeaders"}
index.esm2017.js?2d33:78 [2021-12-06T19:48:29.475Z]  @firebase/firestore: Firestore (9.5.0): Connection Opening WebChannel transport.
index.esm2017.js?2d33:78 [2021-12-06T19:48:29.478Z]  @firebase/firestore: Firestore (9.5.0): Connection WebChannel sending: {"database":"projects/next-sciencesky/databases/(default)","addTarget":{"documents":{"documents":["projects/next-sciencesky/databases/(default)/documents/users/gYYsdl24vQe3nHZRk752zV4FVsH3"]},"targetId":2}}
index.esm2017.js?2d33:78 [2021-12-06T19:48:29.608Z]  @firebase/firestore: Firestore (9.5.0): Connection WebChannel transport opened.
index.esm2017.js?2d33:78 [2021-12-06T19:48:29.752Z]  @firebase/firestore: Firestore (9.5.0): Connection WebChannel received: {"targetChange":{"targetChangeType":"ADD","targetIds":[2]}}
index.esm2017.js?2d33:78 [2021-12-06T19:48:29.752Z]  @firebase/firestore: Firestore (9.5.0): Connection WebChannel received: {"targetChange":{"targetChangeType":"REMOVE","targetIds":[2],"cause":{"code":7,"message":"Missing or insufficient permissions."}}}
index.esm2017.js?2d33:78 [2021-12-06T19:48:29.757Z]  @firebase/firestore: Firestore (9.5.0): MemoryPersistence Starting transaction: Release target
Uncaught (in promise) FirebaseError: Missing or insufficient permissions.
    at eval (index.esm2017.js?a9d0:4327)
    at ns (index.esm2017.js?a9d0:4336)
    at to.onMessage (index.esm2017.js?a9d0:11273)
    at eval (index.esm2017.js?a9d0:11227)
    at eval (index.esm2017.js?a9d0:11250)
    at eval (index.esm2017.js?a9d0:15093)
    at eval (index.esm2017.js?a9d0:15126)

Because I do not know what is the difference between setLogLevel() from firebase/app and setLogLevel() from firebase/firestore, I did that:

// firebase.js
import { setLogLevel } from "firebase/app"
import { setLogLevel as firestoreLogLevel } from "firebase/firestore"

firestoreLogLevel("debug");

const firebaseConfig = {}

const app = initializeApp(firebaseConfig)
// etc.

which tells me that in the console:

[2021-12-06T20:06:55.166Z]  @firebase/firestore: Firestore (9.5.0): AsyncQueue Visibility state changed to hidden
index.esm2017.js?2d33:78 [2021-12-06T20:06:55.369Z]  @firebase/firestore: Firestore (9.5.0): AsyncQueue Visibility state changed to visible
index.esm2017.js?2d33:78 [2021-12-06T20:06:59.475Z]  @firebase/firestore: Firestore (9.5.0): FirebaseCredentialsProvider Auth detected
index.esm2017.js?2d33:78 [2021-12-06T20:06:59.478Z]  @firebase/firestore: Firestore (9.5.0): FirestoreClient Received user= Ude0SAdGpkeEnmNVz00NOMsoO9R2
index.esm2017.js?2d33:78 [2021-12-06T20:06:59.479Z]  @firebase/firestore: Firestore (9.5.0): FirestoreClient Using default OnlineComponentProvider
index.esm2017.js?2d33:78 [2021-12-06T20:06:59.480Z]  @firebase/firestore: Firestore (9.5.0): FirestoreClient Using default OfflineComponentProvider
index.esm2017.js?2d33:78 [2021-12-06T20:06:59.480Z]  @firebase/firestore: Firestore (9.5.0): FirestoreClient Initializing OfflineComponentProvider
index.esm2017.js?2d33:78 [2021-12-06T20:06:59.482Z]  @firebase/firestore: Firestore (9.5.0): FirestoreClient Initializing OnlineComponentProvider
index.esm2017.js?2d33:78 [2021-12-06T20:06:59.486Z]  @firebase/firestore: Firestore (9.5.0): MemoryPersistence Starting transaction: Allocate target
index.esm2017.js?2d33:78 [2021-12-06T20:06:59.490Z]  @firebase/firestore: Firestore (9.5.0): MemoryPersistence Starting transaction: Execute query
index.esm2017.js?2d33:78 [2021-12-06T20:06:59.491Z]  @firebase/firestore: Firestore (9.5.0): QueryEngine Using full collection scan to execute query: Query(target=Target(users/Ude0SAdGpkeEnmNVz00NOMsoO9R2, orderBy: [__name__ (asc)]); limitType=F)
index.esm2017.js?2d33:78 [2021-12-06T20:06:59.497Z]  @firebase/firestore: Firestore (9.5.0): Connection Creating WebChannel: https://firestore.googleapis.com/google.firestore.v1.Firestore/Listen/channel {"httpSessionIdParam":"gsessionid","initMessageHeaders":{"X-Goog-Api-Client":"gl-js/ fire/9.5.0","Content-Type":"text/plain","X-Firebase-GMPID":"1:647468793659:web:cc48e6001fb7ae4c92011e","Authorization":"Bearer eyJhbGciOiJSUzI1NiIsImtpZCI6IjQ3OTg5ZTU4ZWU1ODM4OTgzZDhhNDQwNWRlOTVkYTllZTZmNWVlYjgiLCJ0eXAiOiJKV1QifQ.eyJpc3MiOiJodHRwczovL3NlY3VyZXRva2VuLmdvb2dsZS5jb20vbmV4dC1zY2llbmNlc2t5IiwiYXVkIjoibmV4dC1zY2llbmNlc2t5IiwiYXV0aF90aW1lIjoxNjM4ODIxMjE5LCJ1c2VyX2lkIjoiVWRlMFNBZEdwa2VFbm1OVnowME5PTXNvTzlSMiIsInN1YiI6IlVkZTBTQWRHcGtlRW5tTlZ6MDBOT01zb085UjIiLCJpYXQiOjE2Mzg4MjEyMTksImV4cCI6MTYzODgyNDgxOSwiZW1haWwiOiJneXNlbWFuc3Rob21hc0BnbWFpbC5jb20iLCJlbWFpbF92ZXJpZmllZCI6ZmFsc2UsImZpcmViYXNlIjp7ImlkZW50aXRpZXMiOnsiZW1haWwiOlsiZ3lzZW1hbnN0aG9tYXNAZ21haWwuY29tIl19LCJzaWduX2luX3Byb3ZpZGVyIjoicGFzc3dvcmQifX0.IGr4PVH1uStShKzU-zPYNwD2ZGt0NkMEiUK_SYsWDJA6J66hDgUkL1ydOW2WqParuUZSkJwR-DqSjH8P9DGNXizqi6KuxGJnT53BNLbSiArtAYzR6elZnTDPmyuQPPsqdZ2nPMxzw4bJMzBMwYPybWt3NNWA_1AiD4ZhCkC6lwfaCeofs9-mESsJhSrKk_JQFm61gT6JR0d1lUYycharM5w5SUccDp0KP9cNv9LeflYkmQTauSs8zypbMDWG6Galrtw9-R-BaIG-05NrXIUgSlWODvj7Rw6KDGh8qOgcUG_V8clFhu6qgj9d3PulonX3oA7UIoInKO7VGHB_HxPO_g"},"messageUrlParams":{"database":"projects/next-sciencesky/databases/(default)"},"sendRawJson":true,"supportsCrossDomainXhr":true,"internalChannelParams":{"forwardChannelRequestTimeoutMs":600000},"forceLongPolling":false,"detectBufferingProxy":false,"xmlHttpFactory":{"l":null,"j":false},"httpHeadersOverwriteParam":"$httpHeaders"}
index.esm2017.js?2d33:78 [2021-12-06T20:06:59.503Z]  @firebase/firestore: Firestore (9.5.0): Connection Opening WebChannel transport.
index.esm2017.js?2d33:78 [2021-12-06T20:06:59.507Z]  @firebase/firestore: Firestore (9.5.0): Connection WebChannel sending: {"database":"projects/next-sciencesky/databases/(default)","addTarget":{"documents":{"documents":["projects/next-sciencesky/databases/(default)/documents/users/Ude0SAdGpkeEnmNVz00NOMsoO9R2"]},"targetId":2}}
index.esm2017.js?2d33:78 [2021-12-06T20:06:59.566Z]  @firebase/firestore: Firestore (9.5.0): Connection WebChannel transport opened.
index.esm2017.js?2d33:78 [2021-12-06T20:06:59.633Z]  @firebase/firestore: Firestore (9.5.0): Connection WebChannel received: {"targetChange":{"targetChangeType":"ADD","targetIds":[2]}}
index.esm2017.js?2d33:78 [2021-12-06T20:06:59.634Z]  @firebase/firestore: Firestore (9.5.0): Connection WebChannel received: {"targetChange":{"targetChangeType":"REMOVE","targetIds":[2],"cause":{"code":7,"message":"Missing or insufficient permissions."}}}
index.esm2017.js?2d33:78 [2021-12-06T20:06:59.638Z]  @firebase/firestore: Firestore (9.5.0): MemoryPersistence Starting transaction: Release target
index.esm2017.js?a9d0:366 Uncaught (in promise) FirebaseError: Missing or insufficient permissions.
    at eval (index.esm2017.js?a9d0:4327)
    at ns (index.esm2017.js?a9d0:4336)
    at to.onMessage (index.esm2017.js?a9d0:11273)
    at eval (index.esm2017.js?a9d0:11227)
    at eval (index.esm2017.js?a9d0:11250)
    at eval (index.esm2017.js?a9d0:15093)
    at eval (index.esm2017.js?a9d0:15126)

My answer is too big, sorry for that.
I hope it's what you wanted me to do

@dconeybe
Copy link
Contributor

dconeybe commented Dec 6, 2021

That extra logging is perfect. It confirms that the query is being rejected due to security rules. This, however, should never happen if you've configured the "allow all" rules. I have a few things for you to try.

  1. Try it again! It can take time (10 minutes or so) for security rules to get propagated through Google's backend systems. So if you set the "allow all" rules and issued the query immediately you could have received the "Missing or insufficient permissions" error that would later go away once the updated rules get propagated.
  2. Make sure you are working with the security rules for the correct project: "next-sciencesky". Is it possible that you are accidentally looking at or editing the rules for a different Firebase project?
  3. Try creating a brand new Firebase project, enable Firestore and set up its rules. Point your app to the new Firebase project and try again. Perhaps there is some other configuration issue with you Firebase project.
  4. Test your project against the Firestore emulator (you mentioned you would do this anyways).

Good luck, and let me know how this goes.

@ThomasGysemans
Copy link
Author

Hi, I had time to make tests and I have a situation I don't understand.

As you recommended it, I checked if I was editing the rules of the right project. And indeed I was editing the correct rules.

I have tested once again the app, still not working.

However, I have created another project and now it's working! It's great but I don't understand why the first project is annoying me. Besides I want my web app to be stored in this project, not another one, this one only. This project is used by my android app and files are stored in Firebase storage, files that I'll need in my web app. As a consequence, I'm limited to this project and this is not possible for me to migrate the content of the Firebase storage to another project by hand.

The only difference between the new project (working) and the old project (not working) is the use of the Firebase storage feature, the use of the firebase realtime database feature and the use of the App Check feature.

Please, help me understand what I did wrong and how I could fix this.

As I'm talking about App Check, note that I'm a complete noob in that subject, so if you also want to help there is this obscure subject that nobody wants to answer to: App Check with Flutter.

Thank you

@dconeybe
Copy link
Contributor

dconeybe commented Dec 8, 2021

Ok this is good information. Can you try temporarily disabling AppCheck on the next-sciencesky project? That is, set Firestore's AppCheck status to "Unenforced". I wonder if failing AppCheck causes the same error as security rules. If the AppCheck token was being rejected that would explain why your requests are still denied after setting security rules to "allow all".

@ThomasGysemans
Copy link
Author

ThomasGysemans commented Dec 8, 2021

Oh god, I'm sorry but I hate this App Check. Every time I try to use it, I have problems...

My whole problem was coming from the App Check. I unenforced it from the Firestore feature, and it worked, then I enforced it again, and now it's not working lol.

Do you have an explanation? How the permission can be insufficient whereas I have a debug token (which I registered correctly according to the documentation)...

@ehsannas
Copy link
Contributor

ehsannas commented Dec 8, 2021

@CodoPixel You are using the JS SDK version 9.5.0, but Firestore started supporting AppCheck with SDK version 9.6.0.

As a result, the Firestore client inside your SDK does not know how to communicate to AppCheck, and therefore if you turn on AppCheck enforcement you will not be able to access Firestore. Upgrading to the newer version should fix the problem automatically.

I'll close this issue. If you continue to face any issues using the newer SDK please feel free to let us know.

@ehsannas ehsannas closed this as completed Dec 8, 2021
@ehsannas ehsannas assigned ehsannas and unassigned dconeybe Dec 8, 2021
@firebase firebase locked and limited conversation to collaborators Jan 8, 2022
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Projects
None yet
Development

No branches or pull requests

5 participants