Client doesn't have permission to access the desired data in Firebase - angularjs

I have a page that is calling addCheckin() method which is inside a controller. In the controller, I am trying to create a reference as follows:
var ref = firebase.database().ref("users/" + $scope.whichuser + "/meetings/" +$scope.whichmeeting + "/checkins");
$scope.whichuser and $scope.whichmeeting are the $routeParams that I am passing from another route.
Here's my checkin controller-
myApp.controller("CheckinsController",
['$scope','$rootScope','$firebaseArray','$routeParams','$firebaseObject',
function($scope,$rootScope,$firebaseArray,$routeParams,$firebaseObject){
$scope.whichuser = $routeParams.uid;
$scope.whichmeeting = $routeParams.mid;
var ref = firebase.database().ref("users/" + $scope.whichuser + "/meetings/" +$scope.whichmeeting + "/checkins");
$scope.addCheckin = function(){
var checkinInfo = $firebaseArray(ref);
var data={
firstname:$scope.firstname,
lastname:$scope.lastname,
email:$scope.email,
date:firebase.database.ServerValue.TIMESTAMP
}
checkinInfo.$add(data);
}
}]);/*controller*/
There are two errors that I am getting here-
Error 1:
Error: permission_denied at /users/Vp2P1MqKm7ckXqV2Uy3OzTnn6bB3/meetings: Client doesn't have permission to access the desired data.
Error 2:
Error: permission_denied at /users/Vp2P1MqKm7ckXqV2Uy3OzTnn6bB3/meetings/-KT5tqMYKXsFssmcRLm6/checkins: Client doesn't have permission to access the desired data.
And this is what I am tring to achieve-

Go to Firebase console of your app
Select Database From Side Menu --> Select Rule From tabs above --> Update your rule like this
{
"rules": {
".read": true,
".write": true
}
}
hope it solve your problem . thanks :)

Firebase project by default starts with Firestore as database.
This issue can happen if the application uses "Firebase Realtime Database" and permission for it are not configured. Read and write permission for Firebase Realtime Database should be explicitly granted.
To do so, in Firebase console, Database > Pick "Realtime Database" instead of "Firestore Beta" from the dropdown beside Database > Rules > Set
{
/* Visit https://firebase.google.com/docs/database/security to learn more about security rules. */
"rules": {
".read": true,
".write": true
}
}
Hope that help!

As all provided answers include a security issue where everyone could write / delete entries in your database, which for instance could cause extensive costs and or complete loss of data, when used in a bad way.
Of course you need to use firebase authentication features to use those rules, but preventing write access for anonymous should be default. The following rule provides read access to everyone while keeping security.
{
"rules": {
".read": true,
".write": "auth.uid != null"
}
}

None of these answers provide the most secure way to set up the Realtime Database.
You don't want anyone to randomly access or write to your database
Even if the user is authenticated, you don't want them to access other's data
This rule should address all the cases:
{
"rules": {
"users": {
"$uid": {
".read": "$uid === auth.uid",
".write": "$uid === auth.uid"
}
}
}
}

Please register your self in firebase by using the below code
Firebase.auth()
.createUserWithEmailAndPassword(email, password)
.then((data) => console.log(data))
.catch(error => console.log(error))
and authenticate your self using registered email and password by below code
Firebase.auth()
.signInWithEmailAndPassword(email, password)
.then((data) => console.log(data))
.catch(error => console.log(error))
With the below rules in your real time database
{
"rules": {
".read": "auth != null",
".write": "auth != null"
}
}
Then automatically you will be able to access the data from the real time database
var ref = firebase.database().ref("users");
ref.on("value", function(snapshot) {
snapshot.forEach(function(childSnapshot) {
var childData = childSnapshot.val();
var id=childData.id;
console.log(childData);
});
});
While logging out add the below command to logout of the app
Firebase.auth().signOut()

In order to grant access to all authenticated users, go to database rules tab in firebase web console and copy/paste following rules:
{
"rules": {
".read": "auth != null",
".write": "auth != null"
}
}

It appears that the /users/{uid} routes can be written to but they can not be read from. I changed /users to /userx and it immediately began working.

I hope this can help you.
{
".read": true,
".write": "auth !== null && root.child('users').child(auth.uid).child('meetings').val() === true"
}
You can remove the string && root.child('users').child(auth.uid).child('meetings').val() === true"
and the result is the same.

You can also specify the time, till that you wanna allow like this:
Select Database From Side Menu --> Select Rule From tabs above --> Update your rule like this
{
"rules": {
".read": "now < 1672384350000", // 2022-12-30
".write": "now < 1672384350000", // 2022-12-30
}
}

If someone still get the Error: permission_denied after allowing correct read rights and are fetching data with some kind of firebase npm package; it could be because you're trying to read from Realtime Database instead of the Cloud Firestore.
I was using react-redux-firebase npm package for a quick and easy setup. By default it uses the Realtime Database. If you're using Cloud Firestore you need to state that in the config with useFirestoreForProfile set to true.
import { ReactReduxFirebaseProvider } from 'react-redux-firebase';
const store = configureStore();
const rrfProps = {
firebase,
config: {
userProfile: 'users',
useFirestoreForProfile: true // Firestore for Profile instead of Realtime DB
},
dispatch: store.dispatch,
createFirestoreInstance,
};
Probably similar issues with other packages for firebase, like flamelink that support Realtime Database but not Cloud Firestore as stated in this issue.

Related

react native geolocation not asking user permission on android emulator

Hi Im using the below code to successfully get user location, but in the android emulator it is not asking user if they want to share their location (even after I reinstall the app).
The code works which is great....but I really would like the standard alert to appear which says "are you sure you want to share your location with the app"
Any guidance would be appreciated
navigator.geolocation.getCurrentPosition(
(pos) => {
console.log(pos.coords.longitude, pos.coords.latitude);
I think location permission not show again event you reinstall app because phone still remember permissions granted for app. You can check app have permission granted in Android Setting with App (https://www.howtogeek.com/230683/how-to-manage-app-permissions-on-android-6.0/).
Maybe this code can help you
import { PermissionsAndroid } from 'react-native';
async function getLocation() {
try {
const granted = await PermissionsAndroid.request(
PermissionsAndroid.PERMISSIONS.ACCESS_FINE_LOCATION,
{
'title': 'App',
'message': 'are you sure you want to share your location with the app ?'
}
)
if (granted === PermissionsAndroid.RESULTS.GRANTED) {
// permission granted
// do code get location here.
navigator.geolocation.getCurrentPosition(
(pos) => {
console.log(pos.coords.longitude, pos.coords.latitude);
})
} else {
// permission denied
console.log("GPS permission denied")
}
} catch (err) {
console.warn(err)
}
}

Firebase auth != null I can write but can't read

I have been dealing with the authorization in Firebase for two days now and I can't get it to work. Plenty of reading in the documentation and here in stackoverflow and still don't get it. This is how my rules look like...
{
"rules": {
".read": false,
".write": false,
"notes": {
".read": "auth != null",
".write": "auth != null",
".indexOn": "uid"
}
}
}
My data looks like this...
user-notes-very-upper-root
|_notes
|_-ugly_id_for_this_record
| |--date: "Sat Sep 02 2017"
| |--note: "new note from me"
| |__uid: "firebase_ugly_id"
|_-ugly_id_for_this_record
Like I said before, I can write but I can't read. I'm utilizing angularjs 1.6.6 for this. I have a firebase onAuthStateChange in the .run part to listen for authentication changes and I'm able to move arround the app the user obj. My angular code looks like this...
angular.module('userNotes').run(function($rootScope, $window) {
$rootScope.currentUser = null;
firebase.auth().onAuthStateChanged(function(user) {
if (user) {
$rootScope.currentUser = user.uid;
console.log('User logged in from Run: ', user);
} else {
$rootScope.currentUser = null;
console.warn('User logged out from Run: ', user);
$window.location.href = '#!/';
}
});
});
If I change the .read and .write rules that are right after the rules node to true I have no problem reading the data but I don't want that. I want to read data for just authenticated users.
How I can tweak the rules to make just authenticated users to read and write data.
Update Sept 4, 2017
I change the rules to...
{
"rules": {
"notes": {
".read": "auth != null",
".write": "auth != null",
".indexOn": "uid"
}
}
}
These rules don't fix the problem. I'm able to write but not to read. This is the error in the console...
Possibly unhandled rejection: {"data":{"error":"Permission denied"},"status":401
From the Understanding Firebase Realtime Database Rules documentation (emphasis mine),
.read and .write rules cascade, so this ruleset grants read access to any data at path /foo/ as well as any deeper paths such as /foo/bar/baz. Note that .read and .write rules shallower in the database override deeper rules, so read access to /foo/bar/baz would still be granted in this example even if a rule at the path /foo/bar/baz evaluated to false.
You are not able to read because you have ".read": false, which overrides the .read rule inside "notes". This does not explain though why you are still able to write when you shouldn't be because of ".write": false.
Anyway, try removing the ".read": false and ".write": false so that it does not override the rules under "notes".

Firebase: how to require auth to list all nodes, yet allow anonymous read/write to individual nodes?

I'm writing an invitation application, and would like to email individual people unique URLs, e.g.
http://www.example.com/invitation.html?inviteID=-Jkbw6ycU7ZUOipmqlb5
The HTML app contains JavaScript that connects to a particular Firebase, looking up a node by the inviteID from the URL. Example:
https://my-firebase-123#firebaseio.com/-Jkbw6ycU7ZUOipmqlb5
Each top-level node looks roughly like
-Jkbw6ycU7ZUOipmqlb5: {
email: 'joe#gmail.com',
people: [
{name: 'Joe', accept: true},
{name: 'Jane', accept: false}
],
comments: 'Jane can't make it, but I'm looking forward to it!'
}
This already works great! But I'm having trouble understanding how to properly secure the data. I need the recipients to continue to be able to access those URLs without authentication - anyone who supplies a node ID can read and write to that node and its children - and yet I need to require auth to see the Firebase at its top level, so that invitees cannot see (or modify!) anyone else's responses without knowing other inviteIDs. How can I do this?
{
"rules": {
".read": ??
".write": ??
}
}
I expect both .read and .write will need a rule that means something like this:
"You requested a specific child node, not the top level node; otherwise you must be an authorized user (auth != null) to see the top level node."
The app is written in ReactJS and communicates with Firebase roughly like this:
componentWillMount: function() {
var dbAddress = 'my-firebase-123#firebaseio.com/';
this.firebaseRef = new Firebase(dbAddress + this.props.inviteId);
this.firebaseRef.on("value", function(dataSnapshot) {
this.setState(dataSnapshot.val());
}.bind(this));
},
onSend: function() {
this.firebaseRef.set(this.state);
},
I have been reading the various firebase docs trying to find a similar solution.
Assuming your firebase json structure is something like the following:
{ Invitations: {
-Jkbw6ycU7ZUOipmqlb5: {
email: 'joe#gmail.com',
people: [
{name: 'Joe', accept: true},
{name: 'Jane', accept: false}
],
comments: 'Jane can't make it, but I'm looking forward to it!'
}
-Jkbw6ycU7ZUOipmqlb6: {
... another invitation ...
}
-Jkbw6ycU7ZUOipmqlb7: {
... another invitation ...
}
}
I came up with the following security config which appears to do what you require:
{
"rules": {
".read": false,
".write": false,
"invitations": {
"$inviteid": {
".read": true,
".write": true
}
}
}
}
Actually the top level read/write false may be inferred because if I set the config as the following it seems to work in the same way:
{
"rules": {
"invitations": {
"$inviteid": {
".read": true,
".write": true
}
}
}
}
Now I cant seem to be able to browse the invitations as in if I try and mount at the following points I get permission denied (assuming your firebase address is https://my-firebase-123#firebaseio.com/:
this.firebaseRef = new Firebase('https://my-firebase-123#firebaseio.com/');
this.firebaseRef = new Firebase('https://my-firebase-123#firebaseio.com/invitations');
where as mounting at the following level lets me in:
this.firebaseRef = new Firebase('https://my-firebase-123#firebaseio.com/invitations/-Jkbw6ycU7ZUOipmqlb5');
Not sure if what I have done is actually achieving your requirements from a security perspective (i.e. is it actually secure?).
Would appreciate any feedback from the expert firebase community on this approach.

Firebase permission denied right after $createUser

Inside my web-app, Firebase always tells me permission denied while things are working fine in the simulator.
FIREBASE WARNING: set at /users/simplelogin:14 failed: permission_denied
I'm having trouble adding metadata (such as a name) when users register. data is simply a JSON object that contains a name property.
var signup = function (email, password, data) {
firebaseAuth
.$createUser(email, password)
.then(function (user) {
dataRef.child('users').child(user.uid)
.set(data);
}, function (err) {
console.error(err);
});
};
My firebase rules:
{
"rules": {
"users": {
"$user": {
".read": "$user == auth.uid",
".write": "$user == auth.uid"
}
}
}
}
Simulator works fine:
Attempt to write {"name":"Test"} to /users/simplelogin:7 with auth={"uid":"simplelogin:7"}
/
/users
/users/simplelogin:7:.write: "$user == auth.uid"
=> true
Write was allowed.
As #Kato pointed out you need to log the user in yourself after registration before you can do anything.
Firebase createUser docs

Is it possible to set the displayName in Firebase for the anonymous authentication

I'm using Firebase's Simple Login through AngularFire with the anonymous login method and I was wondering if there's anyway to set the displayName property of the user object returned from
$scope.loginObj.$login('anonymous').then(function(user) {
user.displayName // This is an empty string
}
I would like to set displayName and save it back in Firebase so that users can be shown as that displayName property. As far as I know you don't actually write anything to Simple Login yourself. It seems like the only time it's written to is if you're using something like email/password authentication and using $scope.loginObj.$createUser('name', 'password')
This isn't possible in the way you describe, however, you can do this to get the same behavior.
$scope.loginObj.$login('anonymous').then(function(user) {
if (!user) return;
$scope.userRef = (new Firebase('<Your Firebase>.firebaseio.com/users/')).child(user.uid);
$scope.userRef.child('displayName').on('value', function (snapshot) {
user.displayName = shapshot.val();
});
});
// Then elsewhere in your code, set the display name and user.displayName will be updated automatically
$scope.userRef.child('displayName').set("DISPLAY NAME");
You can even back this up with simple Security Rules:
{"rules":
"users": {
"$uid" {
".read": true,
".write": "$uid == auth.uid'
}
}
}
This ensures that only a correctly authenticated user can modify their own display name.

Resources