nuxt-community / firebase-module

🔥 Easily integrate Firebase into your Nuxt project. 🔥
https://firebase.nuxtjs.org
MIT License
641 stars 99 forks source link

Writes to Firestore fail with SSR Auth #549

Closed simeon9696 closed 3 years ago

simeon9696 commented 3 years ago

I'm setting up ssr auth and even though I've successfully logged in the user, the calls to firestore still fail with:

FirebaseError: PERMISSION_DENIED: 
false for 'create' @ L10
    at new e (prebuilt-d16b955d-cdb9e87f.js?6e89:188)
    at eval (prebuilt-d16b955d-cdb9e87f.js?6e89:9964)
    at Y.eval (prebuilt-d16b955d-cdb9e87f.js?6e89:9912)
    at sb (index.esm.js?c7b2:358)
    at E (index.esm.js?c7b2:338)
    at Z.ta (index.esm.js?c7b2:1350)
    at qc (index.esm.js?c7b2:695)
    at sc (index.esm.js?c7b2:588)
    at M.g.Da (index.esm.js?c7b2:561)
    at M.g.bb (index.esm.js?c7b2:523)

My security rules:

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

Function that writes to firestore (inside of a vuex action):

export const actions ={
    async addProduct({ commit, dispatch }, product) {
        try {
            product.dateAdded = this.$fireModule.firestore.FieldValue.serverTimestamp();
            await this.$fire.firestore.collection('products').add({...product});
        } catch (e) {
            return Promise.reject(e)
        }
    },
};

And the relevant bits of nuxt.config.js

  // Modules: https://go.nuxtjs.dev/config-modules
  modules: [
    // https://go.nuxtjs.dev/pwa
    '@nuxtjs/pwa',
    '@nuxtjs/firebase'
  ],

  firebase: {
    config:{
      apiKey: process.env.apiKey,
      authDomain: process.env.authDomain,
      databaseURL: process.env.databaseURL,
      projectId: process.env.projectId,
      storageBucket: process.env.storageBucket,
      messagingSenderId: process.env.messagingSenderId,
      appId: process.env.appId,
      measurementId: process.env.measurementId
    },
    services:{
      analytics: true,
      performance: true,
      auth: { 
        ssr: true,
        initialize: {
          onAuthStateChangedAction: 'auth/onAuthStateChangedAction',
        },
      }, 
      storage:{
        emulatorPort: process.env.NODE_ENV === 'development' ? 9199 : undefined,
        emulatorHost: 'localhost',
      },
      functions: {
        location: 'us-central1',
        emulatorPort: process.env.NODE_ENV === 'development' ? 5001 : undefined,
        emulatorHost: 'http://localhost', 
      }, 

      firestore: {
        emulatorPort: process.env.NODE_ENV === 'development' ? 8080 : undefined,
        emulatorHost: 'localhost',
        enablePersistence:{
          /**
           * Whether to synchronize the in-memory state of multiple tabs. Setting this
           * to 'true' in all open tabs enables shared access to local persistence,
           * shared execution of queries and latency-compensated local document updates
           * across all connected instances.
           *
           * To enable this mode, `synchronizeTabs:true` needs to be set globally in all
           * active tabs. If omitted or set to 'false', `enablePersistence()` will fail
           * in all but the first tab.
           */
          synchronizeTabs: true,

        },
      },
    }
  },

  // PWA module configuration: https://go.nuxtjs.dev/pwa
  pwa: {
    manifest: {
      lang: 'en'
    },
    workbox: {
      importScripts: [
        '/firebase-auth-sw.js'
      ],
      // by default the workbox module will not install the service worker in dev environment to avoid conflicts with HMR
      // only set this true for testing and remember to always clear your browser cache in development
      dev: process.env.NODE_ENV === 'development',
    }
  },

Version

@nuxtjs/firebase: 7.6.1 firebase: 8.6.7 nuxt: 2.15.6

What is Expected?

An authenticated user can make writes to Firestore if the security rules permit. In nuxtServerInit I do see the user information printed out so the login is successful. Just not sure why the writes still fail. Am I supposed to see two service workers running? Right now I only see 'sw.js' is running.

What is actually happening?

Writes are being denied even though the user is authenticated

lupas commented 3 years ago

Hey @simeon9696 As you can read in the documentation:

This does not authenticate the Firebase Client SDK on the server. While you will be able to know if a user is logged in or not and have access to its simplified properties, you won't be able to do authenticated calls on server-side.

So you won't be able to do authenticated calls to Firestore from the server. This is due to the fact that the Firebase JS SDK is a client SDK and not made for server with multiple users.

We have an experimental workaround by using the serverLogin option, but I do not recommend it for production due to its limitations.

br, Pascal

simeon9696 commented 3 years ago

@lupas I understand that bit now, I thought it meant I can't do any calls from nuxtServerInit . Is there a way to force the call to happen on the client then?

lupas commented 3 years ago

@simeon9696 Yes, you can wrap your code in if (process.client)

if (process.client) {
   // your code
}

or you can wrap entire components like so and make that call only in that component:

<client-only placeholder="Loading...">
      <!-- this component will only be rendered on client-side -->
</client-only>

See https://nuxtjs.org/docs/2.x/features/nuxt-components/

Hope that helps.

simeon9696 commented 3 years ago

@lupas It did run on the client but the call to firestore was still denied. I think I'm missing something. If auth ssr is enabled and I sign in with email and password, why do calls that are wrapped in process.browser fail?

lupas commented 3 years ago

@simeon9696 Hard to tell, if you are logged in the calls should be authenticated... :/ If you could reproduce a minimal example and upload it I could have a look, there must be an issue somewhere in your code. I can't see anything in the code you posted above though... :(