Search code examples
javascriptangulargoogle-cloud-firestorefirebase-securityangularfire

Angular FirebaseError Missing or Insufficient Permissions


I'm attempting to allow each user read and write their own data using firestore, but I'm getting an insufficient permissions error. I'm not sure why.

I have these rules in place for my firestore...

rules_version = '2';
service cloud.firestore {
  match /databases/{database}/documents {
      match /users/{uid} {
        allow create: if request.auth != null;
        allow read, write, update, delete: if request.auth != null && request.auth.uid == uid;
      }
  }
}

In my project, I have my service that uses the following function to push the data to angular firebase (yes, it's pretty lengthy)...

constructor(private afs: AngularFirestore){}


addToOrders(artist: string, formInput: AlbumInput) {
    const currentUser = this.authService.currentUser; // uses a getter function to obtain the current user
    const trackingUrl = 'https://tools.usps.com/go/TrackConfirmAction_input?strOrigTrackNum=';
    const newOrder: Order = {
      artistName: artist, 
      album: formInput.selectedAlbum.name, 
      image: formInput.selectedAlbum.images[0].url, 
      orderType: formInput.orderType, 
      trackingUrl: trackingUrl,  
      variant: formInput.variant
    }

    if (formInput.orderType === "shipped") {
      newOrder.trackingNum = formInput.trackingNum;
      
      return of(this.afs.doc(`users/${currentUser.uid}`).collection('shipped').add(newOrder))
        .subscribe({
          next: (() => {
            this.albumAdded$.next(true);
          }), 
          error: (() => {
            this.albumAdded$.next(false);
          })
        });
    } else {
      newOrder.date = formInput.date;

      return of(this.afs.doc(`users/${currentUser.uid}`).collection('preordered').add(newOrder))
        .subscribe({
          next: (() => {
            this.albumAdded$.next(true);
          }), 
          error: (() => {
            this.albumAdded$.next(false);
          })
        });
    }
  }

Is there anything I'm missing in this pattern that would cause such an error?

If I change the rules to users/${user=**}, it does successfully store the data into the users subcollections, but now I can't sign in normally (for some reason, I can sign up despite the methods being nearly identical). Here is my sign in...

signIn(signInForm: SignInForm) {
        return this.afAuth.signInWithEmailAndPassword(signInForm.email, signInForm.password)
        .then((result) => {
            this.isUserData.next(true);
            this.setUserData(result.user!)
                .then(() => {
                    this.router.navigateByUrl("/home");
                });
        }).catch(error => {
            this.errorModal(error); // Modal Generic launches to inform the user
        });
    }

set user data...

setUserData(user: User) {
        const userRef: AngularFirestoreDocument<any> = this.afs.doc(`users/${user.uid}`);
        const userData: User = {
            uid: user.uid,
            email: user.email,
            displayName: user.displayName
        }
        return userRef.set(userData, {
            merge: true
        });
    }

Solution

  • This rule:

    match /users/{uid} {
    

    Allows a user to read their own profile document. It does not allow them to read subcollections under there, which is what you do in this code:

    of(this.afs.doc(`users/${currentUser.uid}`).collection('shipped').add(newOrder))
    

    to allow a user to also read all subcollections of their profile document, use a recursive wildcard (**):

    match /users/{uid=**} {