1
votes
    firebase.initializeApp(config);
    const db = firebase.firestore();

   const googleSignIn = async () => {
        return await Expo.Google.logInAsync({
            androidClientId,
            iosClientId,
            scopes: ['profile', 'email'],
        });
    };

    const firebaseLogin = async (accessToken) => {
        const cred = firebase.auth.GoogleAuthProvider.credential(null, accessToken);
        await firebase.auth().signInWithCredential(cred).catch(console.error);
        const idToken = await firebase.auth().currentUser.getIdToken(true).catch(console.error);
    };

await firebaseLogin(googleSignIn().accessToken);
db.collection("any").doc().set({test: "OK"})

I get a permission denied error when trying to write to Firestore using a request.auth.uid != null; security rule, but when I replace it with true it works.

It seems that the Firestore component of the web SDK does not send authentication details, even though the API on the client reports Firebase is logged in, and the user last login date appears in the web GUI.

Do I need to pass authentication details to the Firestore component when logging in directly with Google (instead of using the Firebase login APIs)?

The code is running in a React Native app via Expo.

Another example that gets a permission denied:

firebase.auth().onAuthStateChanged((user) => {
    if (user) {
        firebase.firestore().collection("any").doc().set({test: "OK"});
    }
});

Rules

// This is OK:
    service cloud.firestore {
      match /databases/{database}/documents {
        match /any/{doc} {
            allow read, write: if true;
        }
      }
    }

// Permission denied
    service cloud.firestore {
      match /databases/{database}/documents {
        match /any/{doc} {
            allow read, write: if  request.auth.uid != null;
        }
      }
    }

Related

1
Auth works fine with Firestore. However, your code doesn't reveal very much of what you're doing. Nothing happens with db. - Doug Stevenson
Code is just to show how I am logging in, have updated. - zino
Have you tried using an auth state listener to find out when the SDK knows for a fact that your credentials are ready? FYI you are also not passing a string to doc(). - Doug Stevenson
doc() without an argument means "auto-create an ID" - zino
I am encountering the same issue as Zino n i m also using expo. someone posted on this as well. I havent tried downgrading expo to test it out stackoverflow.com/questions/48054884/… - Hendry Lim

1 Answers

0
votes

This solution, and possibly this whole issue, may be specific to React Native.

In a similar question, Jade Koskela noticed that requests were missing the Origin header, and applies a patch to React's XHRInterceptor to work around the missing auth object:

const xhrInterceptor = require('react-native/Libraries/Network/XHRInterceptor');
xhrInterceptor.setSendCallback((data, xhr) => {
  if(xhr._method === 'POST') {
    // WHATWG specifies opaque origin as anything other than a uri tuple. It serializes to the string 'null'.
    // https://html.spec.whatwg.org/multipage/origin.html
    xhr.setRequestHeader('Origin', 'null');
  }
});
xhrInterceptor.enableInterception();