Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Flutter Firestore Authentication

I have a Flutter project that's using the cloud_firestore plugin for data access. Once a user authenticates to the application, what do I need to do to set that as the authentication used by the Firestore client? For example, I just have these basic rules enabled:

service cloud.firestore {
  match /databases/{database}/documents {
    match /users/{userId} {
      allow read, update, delete: if request.auth.uid == userId;
      allow create: if request.auth.uid != null;     
    }
    match /users/{userId}/{document=**} {
      allow read, update, delete, create: if request.auth.uid == userId;
    }
    match /ingredients/* {
      allow read, create: if request.auth.uid != null;      
    }
    match /units/* {
      allow read, create: if request.auth.uid != null;      
    }
    match /recipes/* {
      allow read, create, update: if request.auth.uid != null;      
    }
  }
} 

As soon as I enabled those rules, every request from my Flutter app started failing. If I test the Firestore rules with the little "simulator" they have, they work as expected, so the authentication does not appear to be getting set correctly from the Flutter app side.

EDIT: Adding some code samples.

I have authentication code that uses Google Auth, so when the user logs in it looks like this:

class Auth implements AuthService {
  final FirebaseAuth _firebaseAuth = FirebaseAuth.instance;

GoogleSignIn _googleSignIn = GoogleSignIn(
    scopes: [
      'email',
      'https://www.googleapis.com/auth/contacts.readonly',
    ],
  );


  Future<String> signInWithGoogle() async {
    final GoogleSignInAccount googleUser = await _googleSignIn.signIn();
    final GoogleSignInAuthentication googleAuth = await googleUser.authentication;

    final AuthCredential credential = GoogleAuthProvider.getCredential(
      accessToken: googleAuth.accessToken,
      idToken: googleAuth.idToken,
    );

    final FirebaseUser user = await _firebaseAuth.signInWithCredential(credential);
    return user.uid;
  }

I've verified that the user is being authenticated properly.

Then, when accessing Firestore, something like:

DocumentSnapshot userSnapshot = await Firestore.instance
          .collection('users')
          .document(userId)
          .collection('shoppingLists')
          .document(listName)
          .get();

I've followed all of the guides to add Firebase and Firestore to my app, and I didn't see anything specific about setting the currently authenticated user as the user that's making the Firestore requests, so I feel like I'm missing something there. Is there something I'm supposed to be doing when making the Firestore queries to pass in the current user?

like image 605
cloudwalker Avatar asked Jul 13 '19 01:07

cloudwalker


People also ask

How does authentication work in Flutter?

Authentication state. Firebase Auth provides many methods and utilities for enabling you to integrate secure authentication into your new or existing Flutter application. In many cases, you will need to know about the authentication state of your user, such as whether they're logged in or logged out.


1 Answers

The answer is to not user Firestore.instance as this gives you an instance disconnected from your Firebase app;

instead use create you Firebase app providing all the keys, then authenticate against that app, and then create a Firestore instance against that app. There's no way to explicitly pass the user, but the code internally uses some logic to figure out user that's been authenticated against your created app. Here's the code I used:

  Future<void> _authenticate() async {
    FirebaseApp _app = await FirebaseApp.configure(
      name: 'some-name',
      options: FirebaseOptions(
        googleAppID: 'some:id',
        gcmSenderID: 'sender',
        apiKey: 'api-key-goes-here',
        projectID: 'some-id',
      ),
    );
    final _auth = FirebaseAuth.fromApp(_app);
    final _result = await _auth.signInAnonymously();

    setState(() {
      app = _app;
      auth = _auth;
      user = _result.user;
      store = Firestore(app: app); //this is the code that does the magic!
    });
  }

as for the serverside rule configuration - refer to @cloudwalker's answer

like image 60
dark_ruby Avatar answered Oct 20 '22 00:10

dark_ruby