Login as an admin to a firebase Realtime database through postman - firebase

I have these rules set for a firebase realtime database
{
"rules": {
"adminContent": {
".read": true,
".write": "auth.token.admin === true",
}
}
}
I have created a user and can sign in
following this URL
https://identitytoolkit.googleapis.com/v1/accounts:signInWithPassword?key=[API_KEY]
{
"email":"MY EMAIL",
"password":"MYPASSWORD",
"returnSecureToken":true
}
I get the idToken and all the data.
I input in Params: auth | "THE ID TOKEN RECEIVED"
I am still getting
{
"error": "Permission denied"
}
I am guessing I am supposed to be registered as an admin or get some data as an admin.
I actually need this for a react project but I was testing things in Postman and I don't understand how this thing is working.
I have to keep these rules.
Thank you for your help.

Your security rule requires the user to be an admin:
auth.token.admin === true
But signing the user in does not automatically make then an admin, as that would be a pretty big security risk.
You'll need to run code in a trusted environment that marks the user as an admin. This admin value is known as a custom claim, so I recommend reading the documentation on custom claims and specifically this section on setting custom claims through the Admin SDK.
After doing that, the next time you sign the user in, they'll have that admin claim and it will be passed along to the security rules.

Related

How to set Firebase Database rules? How to prevent .write from deleted user

Introduction
I am building a firebase web client app. I would like set Firebase Database rules.
New user registered to a firebase app. Firebase gave him a user.UID.
Then, admin delete OR disabled the user from firebase admin console.
User refresh client app.
(I find out that) user can still write to firebase database even though his account has been deleted/disabled.
.
Goal / Intention
I would like to set a rule that prevent access (.read OR .write) to firebase database when user does not exist OR disabled in admin console/(auth/users).
Some thing like this:
"rules":{
"$uid":{
".write":"auth.isUserActive(auth.uid) == true"
}
}
.
FIREBASE REFERENCE DOC: https://firebase.google.com/docs/reference/security/database/#auth
Question
How can I achieve the above intention? What are the rules should I set to firebase DB?
Deleting a user doesn't revoke existing tokens for that user. See Firebase authentication not revoked when user deleted?. If you're using one of the standard identity providers, this means that the users may still be able to access the data for an hour after you delete the account.
There is no API for you code to check whether a given uid still exists. And even if such an API existed, it wouldn't help in this case, since a malicious user could just bypass that check and call the API directly.
A simple way to deal with this scenario is to keep a whitelist of allowed or blacklist of disallowed users in your database. For a blacklist, you'd keep a top-level (world readable, admin only writeable) list of banned/deleted users:
banned
uid12345: true
When your admins delete a user, they also add them to this list.
And then in your security rules, you check and disallow access for banned users. E.g.:
"posts": {
".read": "auth != null && !root.child('banned').child(auth.uid).exists()"
}
You can do it by User Based Security as per the doc -v2
var FirebaseTokenGenerator = require("firebase-token-generator.js");
var tokenGenerator = new FirebaseTokenGenerator(FIREBASE_SECRET);
var token = tokenGenerator.createToken({ "uid": "1", "hasEmergencyTowel": true });
For the above created token, the you could write the rules as follows:
{
"rules": {
"frood": {
".read": "auth.hasEmergencyTowel === false"
}
}
}
This could be called once the UID Scope id about to end.
For reference: User Based Security Doc -v2

How can we guarantee that the email saved by the Firebase user is indeed his own email?

In other words, is there a way to verify that the user (when he sets lets say a users//email ), it is indeed the email id of the user who is logged in?
We are building a firebase application, where certain aspects of the service are delivered via email notifications. We do not want to be sending emails to the wrong user. There seems to be no way to guarantee that the email info written to the users//email path is indeed the same as the email used to login (directly or via google or facebook etc.)
In my opinion, if auth (rules) had in addition to auth.uid an auth.email field it would solve the problem and rules could be written to handle the use case.
The latest release of Firebase Authentication supports email verification.
If an identity provider (email+password, google) supports optional email address verification, that information is made available in the API and in the security rules.(**)
For example, the JavaScript API has an emailVerified property that you can check in your code:
firebase.auth().currentUser.emailVerified
true
In the security rules you can access both the email address and whether it is verified, which makes some great use-cases possible. With these rules for example only an authenticated, verified gmail user can write their profile:
{
"rules": {
".read": "auth != null",
"gmailUsers": {
"$uid": {
".write": "auth.token.email_verified == true &&
auth.token.email.matches(/.*#gmail.com$/)"
}
}
}
}
(**) This applies to Google sign-in and email+password for sure. As far as I know, Facebook will only expose the email address if it's been verified, so you could rely on that.

auth.provider is not set to 'password' when user signs-in with email and password

I am developing an iOS app using Firebase (the newest) and I am having trouble with the auth.provider expression in the security rules when the user is authenticated using an email and password. I expect the auth.provider expression to return password but instead it looks like it returns anonymous.
In the Firebase console, I have enabled Email/Password and Google as providers, and have set up the following security rules:
{
"rules": {
"users": {
"$uid": {
// the user is allowed to read
".read": "auth.uid === $uid",
// the non-anonymous user is allowed to write
".write": "auth.uid === $uid && auth.provider !== 'anonymous'"
// more here, omitted for brevity
}
}
}
}
In my app, when signing in as a user XYZ with an e-mail and password, I am not able to set a value under the /users/XYZ node. I am getting a "permission denied" error. This is not the case with users signing-in with Google credentials, where it works as expected.
It looks like the culprit is the condition auth.provider !== 'anonymous'. For an e-mail/password sign-in, I expect the provider to be equal to password; instead it appears to be set to anonymous. The Firebase documentation lists "password" as a possible value for auth.provider: https://firebase.google.com/docs/reference/security/database/#auth
This issue has bigger ramifications, when one enables the new "anonymous authentication" feature (see https://firebase.google.com/docs/auth/ios/anonymous-auth). As I understand it, using auth.provider in the security rules would allow one to distinguish between an "anonymous" user and a "password" user.
Am I looking at a bug or am I making a beginner's mistake somewhere in my reasoning?
For reference, here are the SDK versions I am using (excerpt from CocoaPods output):
Using Firebase (3.2.1)
Using FirebaseAuth (3.0.2)
Using FirebaseDatabase (3.0.1)
The Firebase team confirmed that there is a bug somewhere on their side and are working for a fix. In the meantime, there is a workaround to be found in the link below:
https://groups.google.com/d/topic/firebase-talk/C-ljg-CCKl0/discussion
The workaround consists of using the following security rule for detecting that the user authenticated using an e-mail address:
auth.token.firebase.identities.email !== null
Not being very helpful, but I wanted to say I have the same issue using the Javascript client API. I've sent a support question to the Firebase team. If I get any updates I'll post them here.

Is there a way to restrict registrations in firebase

Is there a way to restrict users from registering firebase email/password accounts so that new users can't sign up? I have a small app that only a few admins need to have access to(which I've manually created in the Firebase admin) and the way it's setup right now it seems like anybody could inject a little javascript and register an account.
Firebase Simple Login is an abstraction built on top of Firebase Custom Login for convenience. When using the email / password authentication, it's worth keeping in mind that this is just creating a mapping between that email and password, and automatically generating authentication tokens for use in your security rules.
In your specific case, if all of the "admin" users have already been created, you can achieve the behavior you're looking for through security rules. For example, if you want to only allow read / write access to your Firebase data tree to authenticated users in that list, try writing top-level read / write security rules that require that user to be in the "admins" list:
{
".read" : "auth != null && root.child('admins').hasChild(auth.uid)",
".write" : "auth != null && root.child('admins').hasChild(auth.uid)"
}
Those rules above ensure that the user is authenticated (via auth != null) and require that the authenticated user's id is in the list of admins (root.child('admins').hasChild(auth.uid)).
The last step is to actually make those users admins, by writing them to the admins subtree. Let's say you have users 1, 4, and 7 to make admins, update your data tree to reflect the following:
{
...
"admins": {
"1": true,
"4": true,
"7": true
}
}
As a result of this, even if other users are able to generate new email / password mappings using Firebase Simple Login, those mappings will have no impact on your application as it is restricted using security rules.
#RobDiMarco provided a great answer, but it has a flaw.
The rule root.child('admins').hasChild(auth.uid) will pass, in case auth.uid will be an empty string.
You can test this in Firebase Database Security Simulator, clearing out uid field ({ "provider": "anonymous", "uid": ""}).
This rule root.child('admins').child(auth.uid).val() === true will not pass with an empty uid.
You can also turn off new user registration by adding a cloud function that deletes new users upon registration. See this answer:
How to prevent new user registration on Firebase?

how do I implement role based access control in firebase

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

Resources