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?
Related
I was looking for simple authentication mechanism for multiple users in Firebase real-time database. For ex: I don't want all millions of users to login using email and password to access Firebase real-time.
I came across creating custom token from the below documentation.
https://firebase.google.com/docs/auth/admin/create-custom-tokens
I want to understand clearly about that. Is this something that helps to authenticate multiple users (grouped as one) programmatically via custom token instead of each user has to authenticate using email address and password? or This is different from what I thought?
Please advise.
No, custom tokens are used when you have your own database of users that have already signed into your existing service with some other form of credentials that you provide.
If you don't have your own database of users, custom tokens won't help.
Also, there is no such thing as "grouping" users for the purpose of authentication using Firebase Authentication. Each user has their own distinct identity with their own credentials that are dealt with independently of each other.
Custom tokens are used when you have your own authentication service but want to allow your users to access Firebase services. If you want your users to be able to use the database without an email and password, you can use a provider such as Google or use Anonymous authentication, which is when the user is logged in and can access the database, but don't have to prove that they're themselves. You can always add them as an actual user later.
To allow authenticated users to access the database, you can use these rules:
// These rules require authentication
{
"rules": {
".read": "auth != null",
".write": "auth != null"
}
}
Database Rules Docs
There is a difference between when a user signs in (authentication) and when they gain access to your database (authorization).
There is no way to prevent users from authenticating with Firebase Authentication's built-in providers that you've enabled in the Firebase console. But it's quite easy to only allow specific users access to the data in your database with Firebase's server-side security rules.
For example, if you only want specific users access, you can set up a whitelist of their UIDs:
allowedUsers
uid1: true,
uid2: true,
uid3: true
Now you can write a simple security rule that only allows users in this list to read your database:
{
"rules": {
".read": "root.child('allowedUsers').child(auth.uid).exists()"
}
}
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
I am using the Simple Login Email / Password Authentication functionality of Firebase.
I would like to manage users through Forge only. I don't want users to be created via the client app.
However I would still like to let them login/logout though.
Is this possible?
You can't prevent users from being created on the client using simple login. There are two options you can utilize instead:
Simple Login "accounts" are really just tokens
Simple Login is just a convenience wrapper that creates Firebase tokens. There is no limit on how many accounts can be stored and they have no affect on your Firebase usage. With this in mind, there's really no reason you need to restrict creation of accounts.
Instead, just utilize security rules to control access to data. When an admin creates an account, have them also add a profile into the data. If only an admin in Forge is allowed to create the profile, then someone could create an account, but it would be superfluous and pointless, since all it does is give them an inert token.
A security rule to enforce access to data:
".write": "root.child('valid_account/'+auth.uid).exists()"
A security rule that allows users to edit their profile but only Forge (admin: true) to create them:
"profiles": {
"$uid": {
".write": "data.exists() && auth.uid === $uid && newData.exists()"
}
}
Creating your own tokens allows complete control
If you're terribly OCD and don't like that approach, then you can cut out Simple Login. As stated previously, it just creates tokens on your behalf. So simply create your own.
In this way you have complete control over account creation and token generation.
I am using the Simple Login Email / Password Authentication functionality of Firebase.
I would like to manage users through Forge only. I don't want users to be created via the client app.
However I would still like to let them login/logout though.
Is this possible?
You can't prevent users from being created on the client using simple login. There are two options you can utilize instead:
Simple Login "accounts" are really just tokens
Simple Login is just a convenience wrapper that creates Firebase tokens. There is no limit on how many accounts can be stored and they have no affect on your Firebase usage. With this in mind, there's really no reason you need to restrict creation of accounts.
Instead, just utilize security rules to control access to data. When an admin creates an account, have them also add a profile into the data. If only an admin in Forge is allowed to create the profile, then someone could create an account, but it would be superfluous and pointless, since all it does is give them an inert token.
A security rule to enforce access to data:
".write": "root.child('valid_account/'+auth.uid).exists()"
A security rule that allows users to edit their profile but only Forge (admin: true) to create them:
"profiles": {
"$uid": {
".write": "data.exists() && auth.uid === $uid && newData.exists()"
}
}
Creating your own tokens allows complete control
If you're terribly OCD and don't like that approach, then you can cut out Simple Login. As stated previously, it just creates tokens on your behalf. So simply create your own.
In this way you have complete control over account creation and token generation.
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