Skip to content
Advertisement

Firebase: authenticated and guest clients connecting to same Firestore Database

My use case is, I have a web app in which I listen to Firestore collections. One of the collections are for public users where anonymous auth is enough. And the second collection is for logged in users, so I implemented custom token auth following this. https://firebase.google.com/docs/auth/web/custom-auth. Once a user logs in, we start a Web Worker to initialise app and listen to Firestore.

My problem is, when a user logs in, the second subscription, the authenticated one, works, but if I try to go to public page, where I don’t need the auth token, from the same tab, I get this error.

Uncaught (in promise) FirebaseError: Missing or insufficient permissions.
    at new Ur (prebuilt.js:184:9)
    at prebuilt.js:10612:34
    at br.<anonymous> (prebuilt.js:10564:21)
    at Bt (eventtarget.js:351:23)
    at qt (eventtarget.js:481:26)
    at Ir.wa (webchannelbasetransport.js:369:17)
    at Ke (webchannelbase.js:2258:25)
    at Fe (channelrequest.js:951:12)
    at Ne.N.Ia (channelrequest.js:743:10)
    at Ne.N.gb (channelrequest.js:603:10)

Both subscription uses the same firebase app, same configs.

More Info:

these are the rules

function isSignedIn(){
  return request.auth != null;
}

function isDocumentOwner(docid) {
  // checks if user id is the same as the document id
  return isSignedIn() && request.auth.uid == docid;
}
//this collection can be accessed for guest/anonymous users
match /guests/{uid} {
  allow read, write: if isDocumentOwner(uid);
}
//this collection in only accessible for logged in users(JWT token)
match /users/{uid} {
  allow read, write: if isDocumentOwner(uid);
}

And this is the init codes

Guest page:

const app = initializeApp(firebaseConfig);
db = getFirestore(app);
auth = getAuth();
signInAnonymously(auth);

onAuthStateChanged(auth, (loginUser) => {
  if (loginUser) {
    user = loginUser;
  } else {
    unsubscribe();
  }
});

Logged in page:

const app = initializeApp(firebaseConfig);
db = getFirestore(app);
auth = getAuth();
signInWithCustomToken(auth, customToken);

onAuthStateChanged(auth, (loginUser) => {
  if (loginUser) {
    user = loginUser;
  } else {
    unsubscribe();
  }
});

Advertisement

Answer

I figured it out. I connect to the same firebase app from two places. First one from a Web Worker, with custom token auth, second one from a different tab from the same browser with anonymous sign in. When the second connection try to initiate a connection with anonymous auth, it doesn’t work because the app is already initiated with custom tokens, which fails this part of the rule,

request.auth.uid == docid

request.auth.uid is of the one who’s logged in.

Fix:

I had to create another app and a set of configurations to be used for logged in users. and then, I had to give an app name when I initialising and authorising the app.

const app = initializeApp(firebaseConfig, 'new-app');
db = getFirestore(app);
auth = getAuth(app);
signInWithCustomToken(auth, customToken);

onAuthStateChanged(auth, (loginUser) => {
  if (loginUser) {
    user = loginUser;
  } else {
    unsubscribe();
  }
});
User contributions licensed under: CC BY-SA
2 People found this is helpful
Advertisement