2

I am trying to figure out how to authenticate my request to firestore.

I am using https://identitytoolkit.googleapis.com/v1/accounts:signInWithPassword?key=<API_KEY> for both which returns me an idToken of the user.

I do authentication on my routes which work but exposes my firestore still, thus me switching over to using security rules but I can't seem to authenticate any request.

I am using express to handle routes to firestore using this format locally:

GET http://localhost:5001/<PROJECT_ID>/us-central1/database/users/
Rules: allow read, write: if true;

GET https://firestore.googleapis.com/v1/projects/<PROJECT_ID>/databases/(default)/documents/users
content-type: application/json

Response: 200 (And I see all the documents)
Rules: allow read, write: if request.auth != null;

GET https://firestore.googleapis.com/v1/projects/<PROJECT_ID>/databases/(default)/documents/users
Authorization: Bearer {{idToken}}
content-type: application/json

Response: {
  "error": {
    "code": 403,
    "message": "Missing or insufficient permissions.",
    "status": "PERMISSION_DENIED"
  }
}

MORE DETAILED INFO

The code below works, but with firebase other way of getting the data, it bypasses this and will only limit based on security rules.

index.ts

import * as functions from 'firebase-functions';
import * as express from 'express';
import * as cors from 'cors';

import isAuthenticated from './components/middleware/authenticated';
import isAuthorized from './components/middleware/authorized';

import users_all from './users/controllers/all';

const route = express();
route.use(cors({ origin: true }));


route.get('/users', isAuthenticated, isAuthorized({ hasRole: ['admin', 'manager'] }), users_all);

exports.database = functions.https.onRequest(route);

users_all

import { Request, Response } from "express";
import sentry from '../../components/reporting/sentry';
import Fireapp from '../../components/firebase/fireapp';

Fireapp

const all = async (req: Request, res: Response) => {

    try {

        let profiles: any = [];

        /** Retrieve the exact document reference */
        const reference = Fireapp.firestore().collection('users').get()
            .then((documents: firebase.firestore.QuerySnapshot) => {
                documents.docs.forEach((doc: firebase.firestore.DocumentData) => { profiles.push(doc.data()) });
                return profiles;
            });

        return Promise.all([reference]).then((response: any) => {
            res.status(200).send(profiles);
        }).catch((error: any) => { throw error });

    } catch (error) {
        sentry(error, { service: '[GET ALL USER]', level: 'moderate', message: error.message });
        res.status(400).send(error.message)
    }

}

export default all;
Doug Stevenson
  • 297,357
  • 32
  • 422
  • 441
xchrisbradley
  • 416
  • 6
  • 21
  • I use Firebase auth rather than IdentityToolKit, but... Shouldn't your rules read: Rules: allow read, write: if request.auth.uid != null; Your rule is missing the '.uid' from the request. – MurrayR Mar 11 '20 at 17:03
  • Request.auth is the object it receives with uid as a property it should work nevertheless – xchrisbradley Mar 12 '20 at 18:12
  • I just used curl to emulate your identityToolKit and firestore api calls on one of my Firebase projects using the same "request.auth != null" rule you listed ...and it worked. I was able to retrieve documents from a collection. I think what you're doing should work, you're on the right track... Maybe it's just a more detailed syntax issue tripping you up? – MurrayR Mar 13 '20 at 14:27
  • I had a similar error. Turns out it was because I was trying to access subcollections, but the rule is not recursive by default. Adding a recursive wildcard to the rule made it work. See my answer at https://stackoverflow.com/a/63929181/1460448 – xji Sep 16 '20 at 23:25

0 Answers0