Closed. This question needs details or clarity. It is not currently accepting answers.
Want to improve this question? Add details and clarify the problem by editing this post.
Closed last year.
Improve this question
I have ploblems with English. I apologize in advance.
Problems with firestore and auth
Error: [firestore/permission-denied] The caller does not have permission to execute the specified operation.
NativeFirebaseError: [firestore/permission-denied] The caller does not have permission to execute the specified operation.
My rules in FireStore:
rules_version = '2';
service cloud.firestore {
match/databases/{database}/documents {
match /Users/{document=**} {
allow read, get: if true;
allow create, update: if request.auth.uid == resource.id;
}
}
I using npm package:
#react-native-firebase/app
#react-native-firebase/app-check
#react-native-firebase/auth
#react-native-firebase/firestore
My code:
import auth from '#react-native-firebase/auth';
import firestore from '#react-native-firebase/firestore';
async function onAuthChanged(onChange) {
auth().onAuthStateChanged(onChange);
}
async function authenticateUser(status) {
if (status) {
const uid = status.uid;
let user = await firestore().collection('Users').doc(uid).get(); // Error
return ({
user: {...user.data(), uid} ?? {login: undefined, birthday: undefined, uid}
});
} else {
return { user: null };
}
}
onAuthChanged(async (status) => {
const { user } = await authenticateUser(status);
});
P.S. In fireStore my rules work: enter image description here
P.S.S. This is my first time working with Firebase and everything worked for the first two weeks with standard rules, but today it gives an error. and I do not know why. Although they offer me to put true on all the rules. This does not help in any way for 6-7 hours I have been trying to understand, so I have already turned here.
In firestore, if you got any permission denied. This is because firestore security rules.
Change your rules to:
service cloud.firestore {
match /databases/{database}/documents {
match /{document=**} {
allow read, write: if true;
}
}
}
Related
I am using react and have logged in user using firebase auth and storing the uid app context.
Security rules:
rules_version = '2';
service cloud.firestore {
match /databases/{database}/documents {
match /{document=**} {
allow read;
allow write: if
request.auth!=null;
}
}
}
I want to keep this security rules.
I want to make request with uid. How do i do that?
This way gives error.
await db.collection('users').doc(uuid).set({name:name});
Uncaught (in promise) FirebaseError: Missing or insufficient permissions.
How do i pass uid as parameter to each request while writing to the database?
It's not clear how you initialize uuid right now, but it should be:
firebase.auth().onAuthStateChanged((user) => {
if (user) {
var uuid = user.uid;
await db.collection('users').doc(uuid).set({name:name});
} else {
// User is signed out
// ...
}
});
This snippet comes pretty directly from the Firebase documentation on getting the current user.
I have chatrooms stored in Cloud Firestore that need to be secured and I'm having a difficult time doing so. My state in React looks as such:
export class Messages extends React.Component {
constructor(props) {
super(props);
this.boardID = this.props.settings.id;
this.mainChatRef = database
.collection("boards")
.doc(boardID)
.collection("chats")
.doc("MAIN")
.collection("messages");
this.chatRoomsRef = database
.collection("boards")
.doc(boardID)
.collection("chats");
}
My query in react looks like:
latestMessages = (messageSnapshot) => {
const message = [];
messageSnapshot.forEach((doc) => {
const { text, createdAt, uid } = doc.data();
message.push({
key: doc.id,
text,
createdAt,
uid,
});
});
this.setState({
dataSource: message,
});
}
queryRooms = async () => {
const recentQuery = await this.chatRoomsRef
.where("uidConcat", "in", [
this.props.user.uid + this.state.value.objectID,
this.state.value.objectID + this.props.user.uid,
])
.get();
for (const qSnap of recentQuery.docs) {
const messagesRef = this.chatRoomsRef
.doc(qSnap.id)
.collection("messages")
.orderBy("createdAt")
.limitToLast(30);
messagesRef.onSnapshot(this.latestMessages);
}
}
My database structure:
boards(collection)
{boardId}
chats (collection)
MAIN
{chatId_1}
{chatId_2}
uidArray (has only two UIDs since it's for private chat)
uidConcat: user1_uid+user2_uid
messages(collection)
{message1}
createdAt
text
uid_creator
uidArray (has UID of user1 and user2)
I tried securing my boards as such:
rules_version = '2';
service cloud.firestore {
match /databases/{database}/documents {
match /boards/{boardId} {
allow read, write: if request.time < timestamp.data(2050, 5, 1);
match /chats/MAIN/messages/{messagesId=**} {
allow read, create: if request.auth.uid !=null;
}
match /chats/{chatId} {
allow read, write: if request.auth.uid !=null;
match /messages/{messagesId=**} {
allow read: if (request.auth.uid in get(/databases/{database}/documents/boards/
{boardId}/chats/{chatId}/messages/{messageId}).data.uidArray)
&& request.query.limit <= 30 && request.query.orderBy.createdAt == 'ASC';
allow write: if request.auth.uid != null;
}
}
}
}
}
I wish to have anyone that's authenticated to always have access to the boards MAIN chat and the way I have it written it works. For private rooms I keep getting an error. I've read the documents and I know that Security rules are not filters which is why I added a bunch of AND statements in an attempt to closely resemble my securities to my written code query in React yet I still keep getting Uncaught Errors in snapshot listener: FirebaseError: Missing or insufficient permissions. I am currently writing my rules to secure at the document level within the messages collection but Ideally I'd like to secure at the document level in the chat colection and check if my request.auth.uid is in the document field uidArray as so :
match /chats/{chatId=**} {
allow read, write if request.auth.uid in resource.data.uidArray
}
I imagine securing the documents in the chat collection would be more secure but any method that secures messages is more than appreciated.
The problem is that you're attempting to do a dynamic lookup in your rule based on each row of the data in this line: get(/databases/{database}/documents/boards/{boardId}/chats/{chatId}/messages/{messageId}).data.uidArray)
The critical point to understand here is that rules do not look at the actual data when perform queries. Get operations are a bit different because there's exactly one record to fetch, but for queries, it only examines the query to ensure it cannot fetch data that doesn't match your rule; it never actually loads data to examine. This is covered in docs here and there's a good video overviewing this here. A deeper dive is here.
Role based access is a complex topic and probably not easy to answer in a Stack Overflow given how broad the solutions would be, and how specific they are to your use case. But a naïve alternative would be to list the members in /chats/{chatId} and use a rule like this:
match /chats/{chatId} {
// scoped to chats/{chatId} doc
function isChatMember(uid) {
// assumes this document contains an array of
// uids allowed to read the messages subcollection
return uid in resource.data.members;
}
match /messages/{messagesId=**} {
allow read: if isChatMember(request.auth.uid)
}
}
I am trying to integrate Stripe payments on my webapp using Firebase. I have cloned the code from the repository here: https://github.com/firebase/functions-samples/tree/master/stripe and have followed the documentation here: https://firebase.google.com/docs/use-cases/payments
From reading the documentation, I assumed that when a customer signed in through firebase authentication, their details would be added to a stripe_customer collection in the firestore. I realised this wasn't the case, and manually added a user to test the save card functions. Then I received the following error : "Invalid value for stripe.confirmCardSetup intent secret: value should be a client_secret string. You specified: undefined"
I have a blaze plan for firebase and have configured. From following the steps in the documentation, I assumed this would be working. I'm sorry this question is so vague, but it seems at every corner I'm getting another issue. Is there something very obvious I am missing that is stopping this code from working? I am trying to implement this for a friends business as a favor, and am getting really confused with Firebase. I am coding in Angularjs. Would greatly appreciate any help on this!
This is the code for the function to create a customer
exports.createStripeCustomer = functions.auth.user().onCreate(async (user) => {
const customer = await stripe.customers.create({ email: user.email });
const intent = await stripe.setupIntents.create({
customer: customer.id,
});
await admin.firestore().collection('stripe_customers').doc(user.uid).set({
customer_id: customer.id,
setup_secret: intent.client_secret,
});
return;
});
And this is the code being called in the controller:
const firebaseUI = new firebaseui.auth.AuthUI(firebase.auth());
const firebaseUiConfig = {
callbacks: {
signInSuccessWithAuthResult: function (authResult, redirectUrl) {
// User successfully signed in.
// Return type determines whether we continue the redirect automatically
// or whether we leave that to developer to handle.
return true;
},
uiShown: () => {
document.getElementById('loader').style.display = 'none';
},
},
signInFlow: 'popup',
signInSuccessUrl: '/checkout.html',
signInOptions: [
firebase.auth.GoogleAuthProvider.PROVIDER_ID,
firebase.auth.EmailAuthProvider.PROVIDER_ID,
],
credentialHelper: firebaseui.auth.CredentialHelper.NONE,
// Your terms of service url.
tosUrl: 'https://example.com/terms',
// Your privacy policy url.
privacyPolicyUrl: 'https://example.com/privacy',
};
firebase.auth().onAuthStateChanged((firebaseUser) => {
if (firebaseUser) {
currentUser = firebaseUser;
firebase
.firestore()
.collection('stripe_customers')
.doc(currentUser.uid)
.onSnapshot((snapshot) => {
if (snapshot.data()) {
customerData = snapshot.data();
startDataListeners();
document.getElementById('loader').style.display = 'none';
document.getElementById('content').style.display = 'block';
} else {
console.warn(
`No Stripe customer found in Firestore for user: ${currentUser.uid}`
);
}
});
} else {
document.getElementById('content').style.display = 'none';
firebaseUI.start('#firebaseui-auth-container', firebaseUiConfig);
}
});
The error you've supplied (below) implies that the key in your config isn't been pulled into your code. If you're running this locally you need to run the below any time you change your functions:config values.
firebase functions:config:get > .runtimeconfig.json
Check the doc's out about how to run your function locally:
Error
"Invalid value for stripe.confirmCardSetup intent secret: value should
be a client_secret string. You specified: undefined"
I have an assignment given by some recruiter and here I need to build an e-commerce site using react redux, and firebase.
The front end part is done but not able to get the data from firebase.
here is my rules Tab content how can I modify it.
this.props.firebase.categories().on('value', snapshot => {
// Not coming here.
console.log(snapshot, snapshot.val)
}, (error) => {
// Error shows here
console.log(error);
});
// Content of Rules tab
service cloud.firestore {
match /databases/{database}/documents {
match /{document=**} {
allow read, write: if true;
}
}
}
Followed this tutorial:
https://www.robinwieruch.de/complete-firebase-authentication-react-tutorial/#react-application-setup
Set read and write permissions to true in rules (firebase).
Closed. This question needs to be more focused. It is not currently accepting answers.
Want to improve this question? Update the question so it focuses on one problem only by editing this post.
Closed 4 years ago.
Improve this question
I am new to NodeJS and Cloud Functions for Firebase, and my website (built in ReactJS) is connected to the Firebase Realtime Database - when customer orders a product all the data he writes in html inputs become stored in my Firebase database.
Now I want to automatically send email containing that data.
From: test#mail.com
Subject: New order for you
Name: "Bla bla"
Product: "Blaa"
you get the point.
I suppose Cloud Functions for Firebase is the answer, could someone help me? What code should I implement in functions/index.js?
EDIT: This is the JSON data from my database:
{
"Email_Message" : {
"-LOOFLA-OFkKY_6Ut03b" : {
"email" : "",
"message" : "",
"name" : ""
}
}
}
Have a look at this official sample from the "Cloud Functions for Firebase Sample Library": https://github.com/firebase/functions-samples/tree/Node-8/email-confirmation
In this sample, the Cloud Function is triggered each time a new node is written (and modified) under the /users main node. You should adapt this path to your own data structure.
Also note that the event handler that is used in the sample is onWrite(), "which triggers when data is created, updated, or deleted in the Realtime Database". If you want to trigger the email sending only when an order is created, you may use the onCreate() handler, see the doc: https://firebase.google.com/docs/functions/database-events
Update, based on your update with the database structure.
Based on your structure you should adapt the Cloud Function sample code as follows:
'use strict';
const functions = require('firebase-functions');
const nodemailer = require('nodemailer');
// Configure the email transport using the default SMTP transport and a GMail account.
// For other types of transports such as Sendgrid see https://nodemailer.com/transports/
// TODO: Configure the `gmail.email` and `gmail.password` Google Cloud environment variables.
const gmailEmail = functions.config().gmail.email;
const gmailPassword = functions.config().gmail.password;
const mailTransport = nodemailer.createTransport({
service: 'gmail',
auth: {
user: gmailEmail,
pass: gmailPassword,
},
});
exports.sendEmailConfirmation = functions.database.ref('/Email_Message/{mailId}').onWrite(async (change) => {
const snapshot = change.after;
const val = snapshot.val();
const mailOptions = {
from: '"......" <youremail#xxxxxxxxx.com>',
to: val.email,
};
// Building Email message.
mailOptions.subject = 'Dear ' + val.name; //for example
mailOptions.text = val.message;
try {
await mailTransport.sendMail(mailOptions);
console.log('email sent to:', val.email);
} catch(error) {
console.error('There was an error while sending the email:', error);
}
return null;
});