Firebase Auth, only activate account created after someone accept it - firebase

I currently have an website that uses firebase auth as my authentication. My problem is that I don't want to open registration to everyone, only a selected few people that are supposed to use the website. I read about .htaccess and .htpasswd but since I'm hosting on firebase hosting I don't think it's possible.
My question is how can I secure the account creation? I don't want to create the accounts manually at firebase console but have the users create it on a page. Is it possible to have the account work only after someone "accept" it at the firebase console or add an extra step after creation, can I somehow protect the registration page if using firebase hosting?

There is no way to prevent any user from creating an account after you enable Firebase Authentication. But the fact that they can create an account, does not necessarily mean that they can then use your application.
The typical approach for your use-case is to store a list of approved users somewhere. Since you're using Firebase Authentication, this would take the form of a list of UIDs.
So to be authorized to use your application a user needs to be authenticated, and approved. Firebase Authentication takes care of them being authenticated, and your back-end functionality should take care of checking their approval status.
For example, if you're using Cloud Firestore as your database, you'd store the approved user UIDs in a collection:
approvedUsers <collection>
UID1 <document>
UID2 <document>
And then you can check in the server-side security rules of your database that the user is authorized (authenticated and approved) before allowing them to (for example) read any data.
exists(/databases/$(database)/documents/$(document.reference))
service cloud.firestore {
match /databases/{database}/documents {
match /myCollection/{document} {
function isApproved() {
return exists(/databases/$(database)/documents/approvedUsers/$(request.auth.uid))
}
allow read, write: if isApproved();
}
}
}

Related

Deleting of an user is not preventing resource access

I am using Firebase Authentication to log in to my app and Firebase Storage to save some files.
The problem is that even I have defined such safety rules for storage:
rules_version = '2';
service firebase.storage {
match /b/{bucket}/o {
match /{allPaths=**} {
allow read, write: if request.auth!=null;
}
}
}
When I delete or disable a user from Authentication Firebase manual panel then this user still can add and remove files to/from our storage.
With above rules I wanted to prevent a user to read/write when he/she is not authenticated.
According to documentation:
https://firebase.google.com/docs/auth/admin/manage-sessions
Refresh tokens expire only when one of the following occurs: - The user is deleted
In theory, it should work. Why it is not? And how to fix it, any idea?
Firebase Authentication uses ID tokens that are valid for one hour. Until the user's existing token expires, they can continue to use that token to access resources. But they won't be able to get a new ID token, so it will take no longer than an hour before they lose full access.
If this is not good enough for your scenario, you'll want to take additional measures to protect the files.
For data in the database, the documentation shows how to detect ID token revocation in security rule. But this approach won't work for Cloud Storage, as you can't perform a lookup of the revoked tokens in there.
For Cloud Storage you could implement your own API to control access to the files, where you'd then perform the same lookup of revoked tokens. That's the only way I can think of to implement immediate revocation.

Is this Firebase/Firestore security rule for anonymously authenticated users safe?

I have a Flutter app that uses an API to pull data. My API key is the only thing stored in my entire Firestore database. My Flutter app retrieves the API key from Firestore and then uses it to fetch data.
My app also has anonymous authentication enabled. My app creates an anonymous user when the app is launched. My app does not allow users to create an account or sign up.
Below are the Firestore security rules that I currently have and I'm unsure if they can be improved to make them more secure from malicious attacks. My rules point to a very specific document myAPIKeyDocument, allows get only for authorized users, and does not allow write.
Are these rules safe as is or can they be improved if the only permission I want my app to grant is read access of my API key for anonymously authenticated users? And also, does if request.auth.uid != null; really make a difference at all since all users of my app will be automatically anonymously authenticated?
rules_version = '2';
service cloud.firestore {
match /databases/{database}/documents {
match /myDataCollection/myAPIKeyDocument {
allow get: if request.auth.uid != null;
allow write: if false;
}
}
}
If any user in your app having access to your API key is secure enough, then yes you are fine. Personally I would migrate any logic that requires an API key out of the client app and into Firebase Functions. That way you can more tightly control security to allow only requests from your app.
With anonymous authentication your current rules are about as good as it gets with the current structure of your project.

Firestore rules for creating a user

I am new to firebase and trying to use firebase authentication, along with firestore database. It looks like all the security lies in rules we set, however I want to know the following:
Is it possible to apply rules based on user authentication without using firebase authentication system ?
How can I make sure that the users are only created through my application ? Would anyone with my firebase credentials (Which are easily exposed in browser) be able to add users to the database ? I understand that there is no domain based locking on firestore, but is user creation atleast domain based ?
Thanks!
Firebase Authentication is the only way to populate the request.auth variable in security rules. So if you want to secure based on a user, you'll need to create that user in Firebase Authentication.
You can however:
Use anonymous authentication to generate a UID for users, without requiring them to enter credentials.
If you have an existing sign-in system, you can hook that up to Firebase Authentication as a custom provider. This would then make your user details available in request.auth in the security rules.
To lock access to your Firestore database down to users from a specific domain, you'd use something like this in your security rules:
request.auth.token.email_verified &&
request.auth.token.email.matches(".*#google.com")
So this only allows access once a user has verified the email address in their profile, and if that email address is from he given domain.

Using Firebase Custom Claims for Admins (Firestore & Cloud Storage)

Giving Admin Rights
I'm using Custom Claims to give admin rights to users, by triggering it when a document in "admins/{userId}" is created.
A Cloud Function then sets the "admin" property in the users custom claims to true. Then the user needs login again and he is admin.
Now I check for the admin Custom Claim in the security Rules of Firestore and Storage, so the user can delete/edit everything.
Revoking Admin Rights???
But when I want to revoke the Admin Rights on a user, how do I make sure that the rights are really revoked everywhere.
For the Firestore I can add an additional check, that also gets the data from the Firestore "admins/{userId}" direction and does not allow access.
BUT if I revoke the Rights and the user does not refresh his token, he can still edit/delete everything in the Firestorage.
And since I can't access Firestore data from the Storage-Security, I can't even double check the "admins/" direction.
So how do I reliably implement an admin functionality for firestore and storage?
As Doug Stevenson says, the token of a 'revoked admin' should expire within an hour after which the refreshed token wouldn't contain the admin custom claim. I think you're on the right track with using Firestore rules to check your 'admins' collection rather than the custom claim.
If immediately revoking rights to Firebase Storage is crucial, you may need to redesign your app so that rather than giving your client direct access to Storage, files can only be accessed through a Firebase Function you build that will validate access authorization against your Firestore 'admins' collection and, if approved, serve the file to the client.

Firebase Web Authentication - Administrator Approval for New Accounts

I've got the Firebase Web Authentication pretty much setup and working for oAuth as well as local username/pwds (email addresses).
My question is: Does anyone have an idea as to how to introduce an additional step in there such that new accounts must be approved by a site administrator prior to being fully validated? I was thinking of tweaking/utilizing the user.emailVerified property but I'm thinking that won't work for oAuth users.
Is there an easy way to do this - to add an admin approval step? Or, is there a property in the Firebase Authentication subsystem that I could easily toggle?
Creating a user via Firebase Authentication only provides them with a unique user id. This doesn't allow them any access to your apps or "register" them in any way. That's entirely your purview. It's nothing more than a map of unique credentials (e.g. Facebook IDs or email/password hashes) to unique Firebase IDs.
You can "register" users by having any access privileges you want, and any workflow to get the user added into your Database (or any other appropriate mechanism).
Assuming database, you would write the user profile/meta data into a path, such as /users/$uid, and base your security rules on whether /users/<user id> exists.
To enforce admin approval, the simplest answer would be to maintain a separate path, such as /registered/<user id>/true that's only accessible by admins (and of course by security rules).
Now you can write rules like the following:
{
"...some path...": {
".read": "root.child("registered/" + auth.uid).val() === true"
}
}
Essentially enforcing a registration process.

Resources