I am currently developing an app that needs a server backend to sync data between devices and also friends. So while researching if I should make my own server (which I'd prefer not to) I stumpled upon Firebase.
What I haven´t figured out is how public data is. From how I understood it, is that whatever I send up could be seen by every user of my app. I saw that you can define rules like "The user needs to be logged in", but can I specify that a certain child should only be visible to the user who created it? And then, is there a way to invite an other user to collaborate on that child? So that now only the creator and the invited user can see that child?
My app would be running on iOS in the beginning, but I guess thats not relevant to my question, is it?
Yes you can do that, you can set security rules to allow only the user with a specific UID (firebase user id) to write or read data like this example...
"users": {
"$uid": {
".read": "auth != null && auth.uid == $uid"
}
}
also with custom authentication you can create your custom claims to grant different access levels (for example admin, editor..etc)
example...
"frood": {
// A towel is about the most massively useful thing an interstellar
// hitchhiker can have
".read": "auth.hasEmergencyTowel === true"
}
and for the invitation part.. you can also grant permission by using a child node as a reference like in this example...
".read": "data.child(auth.uid).exists()",
In the last case.. if the data path requested has a child key that is equal to the uid of the client trying to access it the information will be able to read the data,
all the detailed information is here:
https://firebase.google.com/docs/database/security/user-security#section-revisiting-advanced-example
Related
I have three screens:
Sign Up
log In
HomePage
now, In signup, I have some text field and a profile picture to store.
my question is how and what is the correct way to store data from the signup screen and then use the data to authenticate in the login screen.
Currently, I m using a realtime database from firebase to store data and email and password authenticate.
but rules for the realtime database is this:
{
"rules": {
".read": true,
".write": true
}
}
but I want to use this rule:
{
"rules": {
".read": "auth != null",
".write": "auth != null"
}
}
tell me what is the correct way to do this?
You can use this link Authenticate with Firebase using Password-Based Accounts on Android
The best approach is when a user signs up. You do it with the above code.
After the first authentication success.
You can use the FIrebaseUser.getUId to get the specific users unique identifier and use it as the user's key in a database.
In your databaseRerence you can save the user's data like the following.
FirebaseDatabase.getInstance().getReference().child(FirebaseUser.getUID).setValue(USERDATA)
The USERDATA here is a pojo representing the user's data e.g. name,address,telephone etc
I always structure my apps in a way that am in control of the userflow.
have a splash screen that opens when a user opens my app, the i check if the user was already authenticated in an earlier process.
If firebaseAuth.getCurrentUser returns an object, i know that the user is registered and is already logged in so i will forward him to the Homepage.
If it returns null then i know the user might have logged out or not signed up. In that case i just send him to a login screen in your case log in.
if there weren't signed up they will not be able to proceed to HOmepage so you redirect
them to the Sign up screeen.
Hope that helps. If you don't succeed with this approach. Don't worry the community got you.
After reading lots of tutorials and StackOverflow's questions I still couldn't figure how to do it.
All the tutorials start with the following rule:
"users":{
"$uid":{
".read": "$uid === auth.uid",
".write": "$uid === auth.uid"
}
}
But how to allow a new user in the users node when a new user log in (auth != null) and keep the read and write user-specific path privileges ?
In other words:
Is there a way to make a new user be inserted in the users node after login, and at the same time restrain him to only read and write to his own node ?
Another question. I have a write rule in another node with newData.exists(). In the Simulator when I try to write null data to the node it denies it as expected, but it allows me to write null to a child of this same node. Shouldn't the node write rule cascade to its children ?
The rules you have above will match $uid to auth.uid. So, for example if a user's UID is cKzMyjImSBX6ybzeCCCjf0qbTym1, they will be only be able to read & write at /users/cKzMyjImSBX6ybzeCCCjf0qbTym1 in your database, regardless of whether or not this key currently exists (if it doesn't exist when written to, it will be created).
From the Firebase documentation on rules:
Once a user authenticates, the auth variable in your Firebase Database
Rules rules will be populated with the user's information. This
information includes their unique identifier (uid) as well as linked
account data, such as a Facebook id or an email address, and other
info.
I'm using Firebase for my app and was wondering how to block certain users. I see on the Auth tab of the console, there are "delete" and "disable" options. What do those do? I haven't been able to find documentation on that. Will one of those allow me to block a user?
What I mean by blocking a user is for the ".read": "auth != null" rule to prevent him from accessing data on the database
The disable feature consist in preventing that user to authenticate. So if he tries to authenticate he will fail with error code INVALID_CREDENTIALS and he won't have access to the data that has the ".read": "auth != null" rule. It works like he is deleted but the admin still have the power to reactivate the user account.
If you want to build a list of "blocked users" that will be able to authenticate but will have restricted access, you can store the blocked ids in a node on your firebase database like /databaseRoot/blockedUsers and then work with the security and rules.
".read": "auth != null && !root.child('blockedUsers').hasChild(auth.uid)"
blockedUsers could look like the tree bellow but you could also add some other info under the userId such as the date this user was blocked.
/databaseRoot
/blockedUsers
userId1 : true
userId2 : true
Adding the user to this list will depend on your necessity. You can do it manually by accessing the firebase console and adding the user id to the node. Or, if you want to block an user based on an event on the application, you could simply call something like
ref.child('blockedUsers').child(userIdToBlock).set(true);
This is my first foray into Firebase & nosql, I come from a SQL background.
Using Simple Login Security Email/Password, how do I limit access to data in Firebase? For example, some user will have access to create a business object (users, customers, categories, etc), others won't. Is there a way to attach a list of permissions to the "auth" variable?
There isn't a way to attach permissions directly to the auth variable (or at least that doesn't seem to be an intended strategy). I'd recommend creating a collection of users organized by auth.uid and you can keep whatever kind of permission attributes you want in there, such that your security rules might something look like this (untested):
{
"rules": {
".read": true,
"users": {
".write": "root.child('users').child(auth.uid).child('role').val() == 'admin'"
}
}
}
Where role is an attribute belonging to all objects in your users collection.
UPDATE
See comment below:
"There isn't a way to attach permissions directly to the auth variable" This changed in 2017. You can now attach custom claims to an auth profile, which are available in security rules. See bojeil's answer and the Firebase documentation for custom claims. – Frank van Puffelen
Firebase launched support for role based access on any user via custom user claims on the ID token: https://firebase.google.com/docs/auth/admin/custom-claims
You would define the admin access rule:
{
"rules": {
"adminContent": {
".read": "auth.token.admin === true",
".write": "auth.token.admin === true",
}
}
}
Set the user role with the Firebase Admin SDK:
// Set admin privilege on the user corresponding to uid.
admin.auth().setCustomUserClaims(uid, {admin: true}).then(() => {
// The new custom claims will propagate to the user's ID token the
// next time a new one is issued.
});
This will propagate to the corresponding user's ID token claims.
You can force token refresh immediately after: user.getIdToken(true)
To parse it from the token on the client, you need to base64 decode the ID token's payload: https://firebase.google.com/docs/auth/admin/custom-claims#access_custom_claims_on_the_client
You can upgrade/downgrade users as needed. They also provided a programmatic way to list all users if you have recurring scripts to change a users' access levels: https://firebase.google.com/docs/auth/admin/manage-users#list_all_users
Looking at this again a year later "Custom Tokens" may be a better option.
https://www.firebase.com/docs/security/guide/user-security.html#section-custom
Due to the thin AngularFire documentation and the differences between it and the default web documentation for Firebase, I'm a little lost on how best to secure Create, Read, Update, and Delete operations with users.
In short, say I have an application that manages stores. Users can be owners of the stores or patrons. Owners should read and edit their own stores in their view and patrons should read all but edit no stores in their view.
I'm concerned about the security of suggested methods by Firebase docs such as
So for example, we could have a rule like the following to allow users
to create comments as long as they store their user id with the
comment:
{
"rules": {
".read": true,
"$comment": {
".write": "!data.exists() && newData.child('user_id').val() == auth.id"
}
}
}
To me, this means that I could hack my application's data by simply passing in my victim's user id when I want to post a comment as them. Am I wrong?
I've read the security documentation thoroughly, several times. I think I need further explanation here. Identifying by a client-exposed parameter is the only method I can find so far.
In the example shown here, auth refers to the authenticated user's token data. This is a special variable set by Firebase during auth() events, and thus not something you could hack at the client. In other words, you would only be able to write a comment if you set the user_id value to your own account id.
The contents of the auth object depend on how the client authenticates. For example, SimpleLogin's password provider puts the following into the auth token: provider, email, and id; any of which could be utilized in the security rules.
It's also possible to sign your own tokens from a server, and of course the sky is the limit here.
But the bottom line is that the token's internal values are provided by a trusted process and not by the client, and thus cannot be altered by a user.