I'm getting permission denied after I have authenticated with Anonymous Auth
[ERROR:topaz/lib/tonic/logging/dart_error.cc(16)] Unhandled exception:
E/flutter (21033): PlatformException(-3, Permission denied, )
...
_getCurrentUser: FirebaseUser({providerId: firebase, uid: DOIL...............u54j1, displayName: , email: , isAnonymous: true, isEmailVerified: false, providerData: [{providerId: firebase, uid: DOIL//////////////54j1, displayName: , email: }]})
My rules on the Firebase DB are
{
"rules": {
//Test rule
// "users": {
// "$uid": {
// ".read": "auth != null && auth.uid == $uid",
// ".write": "auth != null && auth.uid == $uid",
// }
// }
// General rule - closed to everyone but app uses
".read": "auth != null",
".write": "auth != null"
}
}
The code I use to save data - works fine with DB rules set to open to all.
_saveUserData(UserEntry userData) async {
print("_saveUserData jsonData =" userData.toJson().toString());
// SAVE MY DATA TO DB
// tUsers = db reference to the child node users on Firebase
_tUsers.push().set(talentUserData.toJson());
}
What am I doing wrong ? Any assistance is appreciated. Thanks.
In the hope of saving someone a headache. I found the problem to be not getting a fresh instance of the Firebase Database. I created the instance in my main.dart and passed it to my HomePage in the constructor (per the example file in the library).
When I got a fresh instance ...out of desperation debugging...it worked. I can now have anonymous login so that only people who have installed the app can write to the database.
Related
I am using REST API in my vuejs app to access firebase realtime database, I authenticate users using Google provider and get access token.
Whe I try fetching data using access_token https://rtdb-url/uid/products.json?access_token=[access token] user get 401 error.
But if the user was added to "Users and permissions" in project settings it works.
Rule appplied to RTDB
{
"rules": {
"$uid": {
"products": {
".write": "auth != null && $uid === auth.uid",
".read": "auth != null && $uid === auth.uid"
}
}
Apparently, I just needed to use the access token I got and send it to the following endpoint in the POST body:
https://identitytoolkit.googleapis.com/v1/accounts:signInWithIdp?key=
As described in the documentation.
I am trying to access custom fields in my auth for controlling access to my data in firebase, The users field in firebase looks like this
users: {
email: string,
isAdmin: boolean,
name: string
}
I have this rules for ensuring that only admin can read the entire table of orders
"orders":{
"$userOrders": {
".read": "$userOrders == auth.uid || auth.isAdmin == true",
"$eachUserOrder": {
".read": "$userOrders == auth.uid || auth.isAdmin == true",
".write": "!data.exists()"
}
},
".read": "auth.isAdmin === true"
},
In the simulation if I pass this as part of the token it works,
{
"provider": "anonymous",
"uid": "559a9195-e2ab-4039-91ac-877d2afca482",
"isAdmin": true
}
But for users with the field isAdmin set to true on the browser it says permission denied.
util.js:233 FIREBASE WARNING: Exception was thrown by user callback. Error: permission_denied at /orders: Client doesn't have permission to access the desired data.
I don't understand what is wrong at this time.
My app allows anyone to write a new message (the message cannot be updated or deleted), which should then only be visible to authenticated users. The authenticated users can edit the data (which will include things like flag as important, etc.). Think of the app like a private suggestion box (anyone can submit a suggestion but only the admins can view the submitted suggestions). I'm using the Firebase simulator and the following fails but it shouldn't:
Firebase Simulator
Write
Location: messages/
Authenticated: false
Data (JSON)
{
"key": "value"
}
Firebase Database Rules
{
"rules": {
"messages": {
"$message": {
".read": "auth !== null",
".write": "!data.exists() || auth !== null",
},
},
"users": {
".read": "auth !== null",
".write": "auth !== null"
}
}
}
I think that's because you're testing with messages/ whereas only writes to messages/{message-id} would be allowed. Try writing to messages/somethingrandom.
After a user registers, we create a username for the user under /users child.
How can I setup my rules so that only the server can create new users and user data cannot be modified by other users.
Javascript
<script>
var ref = new Firebase("https://myapp.firebaseio.com");
var usersRef = ref.child('users');
var usernameField = $('#usernameInput');
var emailField = $('#emailInput');
var passField = $('#passInput');
$('#submitBtn').click(function() {
ref.createUser({
email : emailField.val(),
password : passField.val()
}, function(error, userData) {
if (error) {
console.log("Error creating user:", error);
} else {
console.log("Successfully created user account with uid:", userData.uid);
usersRef.push({
uid: userData.uid,
username: usernameField.val()
});
}
});
});
</script>
Current rules:
{
"rules": {
"users": {
".indexOn": "username",
"$uid": {
".write": true,
// grants read access to any user who is logged in with an email and password
".read": "auth !== null && auth.provider === 'password'"
}
}
}
}
To set up something so that "only the server can create new users", you can access your database using their Server SDK. This way, you can set rules that only apply to access to the database from the server.
However, if you want a web-based UI for admins to create new users, you need to write a Node.js or Java backend web server (utilizing the Server SDK). You can't use the client-side JS SDK, or Firebase hosting.
Just follow the instructions in the Server Side setup section of their documentation.
Then add the databaseAuthVariableOverride option to initializeApp:
var firebase = require("firebase");
firebase.initializeApp({
serviceAccount: "path/to/serviceAccountCredentials.json",
databaseURL: "https://databaseName.firebaseio.com",
databaseAuthVariableOverride: {
// maybe use something more descriptive and unique
uid: "server-side-app"
}
});
Then the following as your rules (warning: not tested):
{
"rules": {
"users": {
".indexOn": "username",
// grants write access if the authenticated user is accessing
// via the Server SDK
".write": "auth != null && auth.uid === 'server-side-app'",
// grants read access to any user who is logged in with an email/password
".read": "auth != null && auth.provider === 'password'"
}
}
}
There is no concept of "only the server" when you use Firebase. Each user writes their own data, so to secure that you need to use Firebase's User Based Security.
In this case the rules are fairly simple: you want each user to be able to only write to their own node. You can do this by modifying your rules to:
{
"rules": {
"users": {
".indexOn": "username",
"$uid": {
// grants write access to the owner of this user account
// whose uid must exactly match the key ($user_id)
".write": "auth.uid === $uid",
// grants read access to any user who is logged in with an email and password
".read": "auth.uid !== null && auth.provider === 'password'"
}
}
}
}
Note that I copied the .write rule from the first example in the Firebase documentation on User Based Security. So it's probably a good idea to read that page (again), since it explains a lot more than just the answer to this question.
Before in my app I was creating accounts successfully until I put some rules
{
"rules": {
"users": {
"$uid": {
// grants write access to the owner of this user
// account whose uid must exactly match the key ($uid)
".write": "auth !== null && auth.uid === $uid",
// grants read access to any user who is logged in
// with an email and password
".read": "auth !== null && auth.provider === 'password'"
}
}
}
}
then, the accounts are created because I see those accounts in the dashboard. But once I try to create, I am getting this kind of errors
FIREBASE WARNING: set at /users/simplelogin:32 failed: permission_denied
Since you want the user to be able to create their own node initially, you'll need to explicitly allow the case where the location is new.
Based on the documentation on the auth parameter:
".write": "!data.exists() || auth.uid === $uid""
Note: I'm not entirely sure this will work, but felt it'd be more readable as in answer-format than as a "try this" comment.