Business
Jobs
  • About Us
  • Solutions
    • Job Postings
      Post your job and receive qualified candidates in 48h.
    • Candidate Assessments
      500+ technical and psychological tests, plus anti-fraud.
    • Headhunting
      Tailor-made executive search from start to finish.
    • Payroll + EOR
      Payroll dispersal and EOR across 15+ LATAM countries.
  • Pricing
  • Jobs

0

161
Views
Firebase 9, Remix: addDoc() returns "PERMISSION DENIED" error

I have a remix app using firebase & a firestore database.

The sign in works fine, the GET /documents as well (no rules for GET)

When I try to create a new document with addDoc() I get a PERMISSION DENIED error.

My rules:

rules_version = '2';
service cloud.firestore {
  match /databases/{database}/documents {
    match /{document=**} {
      allow create, update, delete: if request.auth != null && request.auth.token.email_verified && request.auth.token.email == 'my_email@gmail.com';
      allow read: if true;
    }
  }
}

Since I use Remix (SSR) I am initializing firebase in the client-side:

if (getApps().length === 0) {
  initializeApp({
    apiKey: "...",
    authDomain: "...",
    projectId: "...",
    storageBucket: "...",
    messagingSenderId: "...",
    appId: "...",
    measurementId: "...",
  });
}

And I have firebase-admin in the server-side:

const serviceAccount = require("~/firebase-service-account.json");
serviceAccount.private_key_id = process.env.FIREBASE_PRIVATE_KEY_ID;
serviceAccount.private_key = process.env.FIREBASE_PRIVATE_KEY;

if (getApps().length === 0) {
  admin.initializeApp({
    credential: admin.credential.cert(serviceAccount),
  });
}

I use Google authentication in the client-side like this:

const submit = useSubmit();

const signInWithGoogle = async () => {
  const provider = new GoogleAuthProvider();
  const { user } = await signInWithPopup(auth, provider);

  if (user) {
    const formData = new FormData();
    formData.set("user", JSON.stringify(user));
    submit(formData, { method: "post" });
  }
};

Then the formData is handled by my server-side code and create a sessionCookie with auth().createSessionCookie().

Everything works fine in my dashboard (only accessible by logged-in users, I am using auth().verifySessionCookie() to check that) until I create a new document with the addDoc function from firebase 9. auth comes from firebase-admin package.

Here is the code I use:

const addDocument = async <T>(name: string, data: T): Promise<T> => {
  console.log(getAuth().currentUser) // null
  await addDoc(collection(db, name), data as Record<string, any>);

  cache().deleteEntry(name);

  return data;
};

When my write rule is set to true it works fine but when I put request.auth != null I have the permission error so I guess the problem is in the authentication part.

about 4 years ago · Santiago Trujillo
1 answers
Answer question

0

While you may be using the Admin SDK on the server, that last code snippet is definitely a regular JavaScript SDK (as the Admin SDK doesn't have the concept of a currentUser). When you sign in the user on the client, that state does not automatically get transported to your server-side code.

The most common approach for accessing Firebase from the server until recently was to use the Admin SDK (which bypasses security rules) and perform any authorization checks in your application code.

You can use the regular JavaScript SDKs on the server, but you will have to ensure their sign-in state yourself. There is some work in progress to do this automatically for Next.js and Angular Universal, but not yet for Remix.run. How these work (and what you'd have to do) is that they:

  1. Pass the sign-in information in session cookies
  2. Verify the ID token in the server-side code with Admin SDK.
  3. If the verification succeeds, they mint a custom token for the user.
  4. And then sign in with that custom token in the regular JavaScript SDK.

You'll need to ensure that you have a separate FirebaseApp/Auth instance for each user, and will probably want to set up a LRU cache for those to prevent having to perform that translation on each call.

about 4 years ago · Santiago Trujillo Report
Answer question
Find remote jobs

Discover the new way to find a job!

Top jobs
Top job categories
Business
Post vacancy Pricing Sales
Legal
Terms and conditions Privacy policy
© 2026 PeakU Inc. All Rights Reserved.
Andres GPT
Show me some job opportunities
There's an error!