How to pass Auth token in FireStore in Web app - javascript

I have developed a single crud project(Login screen and crud operation screen HTML) and hosted on firebase hosting. where User signing with email and password, I am using firebase signing with email and password and its working as expected.
But now issue is I want to secure backend with auth but its not passing auth in setDoc() deleteDoc() etc, My requirement is without auth. no one should do any operation on database.
import { doc, setDoc } from "firebase/firestore";
await setDoc(doc(db, "cities", "LA"), {
name: "Los Angeles",
state: "CA",
country: "USA"
});
below rules are working but its not secured for production env. :
rules_version = '2';
service cloud.firestore {
match /databases/{database}/documents {
match /{document=**} {
allow read, write: if true
}
}
}
If set rules like below it give me insufficient permission error. I don't know how to pass UID in setDoc() or any operation.
allow read, write: if request.auth != null
Update : If i put below code before setDoc() below code is not executing because currentUser has user data.
function addCity(){
if (!firebase.auth().currentUser) {
// this code not executing because user is signed
alert("Login required");
window.href = "login.html";
return;
}
// i can print UID and it is showing means user is logged.
await setDoc(doc(db, "cities", "LA"), {
name: "Los Angeles",
state: "CA",
country: "USA"
});
}

This is in detail covered in the Firebase documentation on Security & Rules, which I would recommend you to check out.You can secure your data with Security Rules,Firebase Security Rules are evaluated and based on that the rules language it is validated whether the current user can access your data.
Security Rules give you access to a set of server variables to check your rules against. The most commonly used one is the auth variable which lets you check against the currently authenticated user. You can also create wildcard variables with the $, which acts as a route parameter creating.
{ "rules": { "users": { // users can read and write their own data, but no one else. "$uid": { ".read": "auth.uid == $uid", ".write": "auth.uid == $uid" } } } }
You can also check the feature called Firebase App Check, it will let you limit access to your Realtime Database to only those coming from iOS, Android and Web apps that are registered in your Firebase project.
You can combine this with the user authentication based security described above, so that you have another shield.
Also check these similar examples below:
How to prevent unauthorized access to Firebase database
How to prevent users from changing the Database data
Allow only authenticated users to modify database data

Finally,
I found solution. I was using different version library of firebase. like I was using web v8 library for login and modular lib for database access. I just moved all firebase SDK to same version and modular.

Related

Firebase Storage Security Rules request being denied

I'm trying to build a basic social media site with profile photos that any user can read, but each user can edit only their own photo. I wrote it after reviewing the documentation here
https://firebase.google.com/docs/storage/security/rules-conditions
and when I use the simulator on the storage settings with a test authenticated user I get a success
Here is a photo of the successful test read: https://i.stack.imgur.com/ZCF5L.png
But I also have tried running this on my deployed app and each request no matter read or write, authenticated or not, I keep getting my request declined
failed storage request from deployed app
These are my security rules:
service cloud.firestore {
match /b/{bucket}/o {
match /internal/profilePhoto/{imageId} {
allow read: if request.auth != null;
allow write: if request.auth.uid == imageId;
}
}
}
and here is my code with the address I'm requesting from
async function upload(file, currentUser, setLoading) {
const fileRef = ref(storage, 'internal/profilePhoto/'+currentUser.uid);
setLoading(true);
console.log(currentUser.uid)
const snapshot = await uploadBytes(fileRef, file);
const photoURL = await getDownloadURL(fileRef);
updateProfile(currentUser, {photoURL});
setLoading(false);
alert("Uploaded file!");
}
Any guidance would be greatly appreciated.
I figured it out. I opened another app with the default testing storage settings and my code let me upload to that database. I looked back at my FIREBASE STORAGE security settings and noticed that that first line said
service cloud.fireststore {
That was my problem. I accidentally copied in a rule setting for cloud firestore which left my storage database without any security rules which I assume made the default no access. If you want to set a rule setting for firebase storage than that rule needs to be
service firebase.storage {
I hope this saves at least one person a few hours of head banging.
The full rule setting I'm using for testing is
rules_version = '2';
service firebase.storage {
match /b/{bucket}/o {
match /{allPaths=**}{
allow read, write: if true;
}
}
}

how to set permissions in firebase firestore

$path = "firebase_auth.json";
$config = array(
"projectId" => "XXXX",
"keyFile" => json_decode(file_get_contents($path), true)
);
$firestore = new FirestoreClient($config);
$collectionReference = $firestore->collection('Channels');
$snapshot = $collectionReference->documents().get();
Response of this code is
An uncaught Exception was encountered
Type: Google\Cloud\Core\Exception\ServiceException
Message: { "message": "Missing or insufficient permissions.", "code": 7, "status": "PERMISSION_DENIED", "details": [] }
Filename: /var/www/html/riglynx/vendor/google/cloud/Core/src/GrpcRequestWrapper.php
Line Number: 263
check out Get started with Cloud Firestore Security Rules documentation. And see Writing conditions for Cloud Firestore Security Rules documentation.
One of the most common security rule patterns is controlling access
based on the user's authentication state. For example, your app may
want to allow only signed-in users to write data:
service cloud.firestore {
match /databases/{database}/documents {
// Allow the user to access documents in the "cities" collection
// only if they are authenticated.
match /cities/{city} {
allow read, write: if request.auth.uid != null;
}
}
}
This should help you get started.
Reason you are getting the error is because you are not allowed to access documents of the collection called Channels.
In order to fix this, you have login to your console firebase.
Navigate to Database > Under firestore database, you have to click on Rules.
Under rules, you can give permission as per your wish.
If you want to give access to al the users then you can simple replace current code with the following code. (Not a good practice and not secure too)
service cloud.firestore {
match /databases/{database}/documents {
match /{document=**} {
allow read, write;
}
}
}

Firebase security rules data.exists() not working

Following the post here I created a simple security rule and cloud function that gets called to see if a username already exists. The problem is that the security rule write check always passes and just sets the new value in that location (/username_lookup/user1).
When I try to write at this location using the realtime database rules simulator it works as expected, i.e. the write is blocked.
Can someone spot the problem?
The firebase security rule
"rules": {
"username_lookup": {
"$username": {
// not readable, cannot get a list of usernames!
// can only write if this username is not already in the db
".write": "!data.exists()",
// can only write my own uid into this index
".validate": "newData.val() === auth.uid"
}
}
}
And the cloud function
var fb = admin.database().ref();
createUser(uid, username);
function createUser(userId, usrname) {
fb.child('username_lookup').child(usrname).set(userId, function(unerr) {
if(unerr) {
res.setHeader('Content-Type', 'application/json');
res.send(JSON.stringify({error: "the_error_code" }));
}
});
}
Screenshot of the username_lookup object/index
You Cloud Functions access the Firebase database through:
var fb = admin.database().ref();
As you can see, the module is admin which indicates that you're using the Firebase Admin SDK. One of the key traits of the Firebase Admin SDK is:
Read and write Realtime Database data with full admin privileges.
source: https://firebase.google.com/docs/admin/setup
So the Admin SDK actually bypasses your security rules.
It's also a pretty bad practice to use an error handler for basic flow control.
Instead, use a Firebase transaction to read/write the location with the name in an atomic way:
fb.child('username_lookup').child(usrname).transaction(function(value) {
if (value) {
res.setHeader('Content-Type', 'application/json');
res.send(JSON.stringify({error: "the_error_code" }));
return; // abort the transaction
}
else {
return userId;
}
});

Firebase: authorisation for edit / delete operations without creating an user login

I created an app where anonymous users can write comments. Now I want them also to edit and delete (only) their comments. Is this possible without using firebase auth?
Since it is only a one-time app for the user its kind of an overkill to create a login for each user.
I tried to store an editKey with the comment-object which should allow the user to edit / delete his comment. (I store this key for the user in a cookie in the browser)
Then somehow deny reading the editKey (".read:" false) via firebase rules. Only allow the write operation when the editKey is known: ".write": "data.val() == newData.val()"
"comments" : {
".read": true,
"$comment_id": {
".write": "!data.exists() && newData.exists()",
"text": {
".validate": "newData.isString()"
},
"created": {
".validate": "newData.isNumber()"
},
"editKey": {
".read": false,
".write": "data.val() == newData.val()",
".validate": "newData.isString()"
},
"visible": {
".validate": "newData.isBoolean()"
},
}
}
But this does not work because the whole comment, which should be public, is not readable when I set the rule ".read:" false for the editKey
Any ideas how this could be achieved without firebase.auth() ?
You are looking for Authenticate with Firebase Anonymously
https://firebase.google.com/docs/auth/web/anonymous-auth#authenticate-with-firebase-anonymously
You can use Firebase Authentication to create and use temporary
anonymous accounts to authenticate with Firebase. These temporary
anonymous accounts can be used to allow users who haven't yet signed
up to your app to work with data protected by security rules. If an
anonymous user decides to sign up to your app, you can link their
sign-in credentials to the anonymous account so that they can continue
to work with their protected data in future sessions.

Firebase - Why is it not pulling my information? [duplicate]

I'm relatively new to coding and am having trouble.
I have this code to send data to firebase
app.userid = app.user.uid
var userRef = app.dataInfo.child(app.users);
var useridRef = userRef.child(app.userid);
useridRef.set({
locations: "",
theme: "",
colorScheme: "",
food: ""
});
However, I keep getting the error:
FIREBASE WARNING: set at /users/(GoogleID) failed: permission_denied
2016-05-23 22:52:42.707 firebase.js:227 Uncaught (in promise) Error: PERMISSION_DENIED: Permission denied(…)
When I try to look this up it talks about rules for Firebase, which seems to be in a language that I haven't learned yet (or it is just going over my head). Can someone explain what is causing the issue? I thought it was that I was asking for it to store email and user display name and you just weren't allowed to do this, but when I took those out I still had the same problem. Is there a way to avoid this error without setting the rules, or are rules something I can teach myself how to write in a day, or am I just way out of my league?
Thanks for any help!
By default the database in a project in the Firebase Console is only readable/writeable by administrative users (e.g. in Cloud Functions, or processes that use an Admin SDK). Users of the regular client-side SDKs can't access the database, unless you change the server-side security rules.
You can change the rules so that the database is only readable/writeable by authenticated users:
{
"rules": {
".read": "auth != null",
".write": "auth != null"
}
}
See the quickstart for the Firebase Database security rules.
But since you're not signing the user in from your code, the database denies you access to the data. To solve that you will either need to allow unauthenticated access to your database, or sign in the user before accessing the database.
Allow unauthenticated access to your database
The simplest workaround for the moment (until the tutorial gets updated) is to go into the Database panel in the console for you project, select the Rules tab and replace the contents with these rules:
{
"rules": {
".read": true,
".write": true
}
}
This makes your new database readable and writeable by anyone who knows the database's URL. Be sure to secure your database again before you go into production, otherwise somebody is likely to start abusing it.
Sign in the user before accessing the database
For a (slightly) more time-consuming, but more secure, solution, call one of the signIn... methods of Firebase Authentication to ensure the user is signed in before accessing the database. The simplest way to do this is using anonymous authentication:
firebase.auth().signInAnonymously().catch(function(error) {
// Handle Errors here.
var errorCode = error.code;
var errorMessage = error.message;
// ...
});
And then attach your listeners when the sign-in is detected
firebase.auth().onAuthStateChanged(function(user) {
if (user) {
// User is signed in.
var isAnonymous = user.isAnonymous;
var uid = user.uid;
var userRef = app.dataInfo.child(app.users);
var useridRef = userRef.child(app.userid);
useridRef.set({
locations: "",
theme: "",
colorScheme: "",
food: ""
});
} else {
// User is signed out.
// ...
}
// ...
});
I was facing similar issue and found out that this error was due to incorrect rules set for read/write operations for real time database. By default google firebase nowadays loads cloud store not real time database. We need to switch to real time and apply the correct rules.
As we can see it says cloud Firestore not real time database, once switched to correct database apply below rules:
{
"rules": {
".read": true,
".write": true
}
}
Note:
Be careful with the rules. By setting read and write to true makes database vulnerable to praying eyes.
Read more:
https://firebase.google.com/docs/database/security
Go to the "Database" option you mentioned.
There on the Blue Header you'll find a dropdown which says Cloud Firestore Beta
Change it to "Realtime database"
Go to Rules and set .write .read both to true
Copied from here.
Go to database, next to title there are 2 options:
Cloud Firestore, Realtime database
Select Realtime database and go to rules
Change rules to true.
OK, but you don`t want to open the whole realtime database!
You need something like this.
{
/* Visit https://firebase.google.com/docs/database/security to learn more about security rules. */
"rules": {
".read": "auth.uid !=null",
".write": "auth.uid !=null"
}
}
or
{
"rules": {
"users": {
"$uid": {
".write": "$uid === auth.uid"
}
}
}
}
Open firebase, select database on the left hand side.
Now on the right hand side, select [Realtime database] from the drown and change the rules to:
{
"rules": {
".read": true,
".write": true
}
}
Another solution is to actually create or login the user automatically if you already have the credentials handy. Here is how I do it using Plain JS.
function loginToFirebase(callback)
{
let email = 'xx#xx.com';
let password = 'xxxxxxxxxxxxxx';
let config =
{
apiKey: "xxx",
authDomain: "xxxxx.firebaseapp.com",
projectId: "xxx-xxx",
databaseURL: "https://xxx-xxx.firebaseio.com",
storageBucket: "gs://xx-xx.appspot.com",
};
if (!firebase.apps.length)
{
firebase.initializeApp(config);
}
let database = firebase.database();
let storage = firebase.storage();
loginFirebaseUser(email, password, callback);
}
function loginFirebaseUser(email, password, callback)
{
console.log('Logging in Firebase User');
firebase.auth().signInWithEmailAndPassword(email, password)
.then(function ()
{
if (callback)
{
callback();
}
})
.catch(function(login_error)
{
let loginErrorCode = login_error.code;
let loginErrorMessage = login_error.message;
console.log(loginErrorCode);
console.log(loginErrorMessage);
if (loginErrorCode === 'auth/user-not-found')
{
createFirebaseUser(email, password, callback)
}
});
}
function createFirebaseUser(email, password, callback)
{
console.log('Creating Firebase User');
firebase.auth().createUserWithEmailAndPassword(email, password)
.then(function ()
{
if (callback)
{
callback();
}
})
.catch(function(create_error)
{
let createErrorCode = create_error.code;
let createErrorMessage = create_error.message;
console.log(createErrorCode);
console.log(createErrorMessage);
});
}
PermissionDenied can also appear if provided Firebase project ID is incorrect.
See this guide to check your project ID:
Firebase console: Click settings Project settings. The project ID is displayed in the top pane.
If you are attempting to reuse an old project in firebase, due to free account restrictions, then your database rules are probably outdated.
In my case, I was getting error 401 Unauthorized and it solved when I set both read and write rules equal to true.
Thanks for this great community!
Much respect from Brazil!
i was also having the same problem. make sure that you are using the real-time database instead of the cloud. then change rules to allow access to all users as follows
{
"rules": {
".read": true,
".write": true
}
}
by default the firestore database only allows admins to read and write from the database thus the read/write rules will be set to false.

Categories

Resources