Reputation: 1423
I have a Sign Up Flow using Firebase. When I check if an email already exists in the database, like so:
refUsers.queryOrdered(byChild: "email").queryEqual(toValue: emailText).observeSingleEvent(of: .value, with: { snapshot in
if (snapshot.value is NSNull) {
print("Unique email")
// Move to Password View.
let passwordViewController = self.storyboard?.instantiateViewController(withIdentifier: "PasswordViewController") as! PasswordViewController
self.navigationController?.present(passwordViewController, animated: true, completion: nil)
// Pass the emailText to the last View of the flow.
self.singleton.sharedInstance.emailText = emailText!
}
else {
print("Duplicate email")
}
})
The problem is, I don't have the permission to view /users in the database cause my rule is:
{
"rules": {
".read": "auth != null",
".write": "auth != null"
}
}
I know I can find if an email is a duplicate using Auth.auth().createUser
but it's not just email that I'm checking in the sign up flow. I use the same method for unique username, as well. How can I achieve this?
Upvotes: 4
Views: 4291
Reputation: 1379
As you can see this is not the best way to do it. You should not manually check if email already exists - Firebase can do that for you when user signs up and why would you not want to use that?
What you need is a different approach. I can think of two ways right now:
First:
You can add a new rule to Firebase, eg:
{
"rules": {
"usernames": {
".read": true,
".write": "auth != null"
},
"emails": {
".read": true,
".write": "auth != null"
}
}
}
What you do here is create a new node named usernames
which every user can access and read.
Here you should hold a copy of all usernames that registered users have and when registering check if users username is already inside this node.
Second way:
You could modify your signup flow a bit and let users register without a username. After account is created you let them set a username. With a nice flow it would all look as the same registration form.
UPDATE
With rules above users should be able to read from emails
and usernames
without being registered. This way you can fetch data and compare if email or username is already in use.
Just make sure that when user registers you insert his email and username into those two nodes.
Upvotes: 6
Reputation: 1423
Though @ZassX answered helped me, I've learned what a good approach for this would be, for those who are confused like me.
The best approach is to keep users data safe in /users
with "auth != null"
rule. Only show the user's meta data to everyone that includes just the email and password of each user. For example:
Database
{
“metaData”: {
uid: {
“email”: …,
“password”: …
}
},
“users”: {
uid: {
“email”: …,
“password”: …
// other information
}
}
}
Security
{
"rules": {
“metaData”: {
“.read”: true,
“.write”: “auth !== null”
},
“users”: {
“.read”: “auth !== null”,
“.write”: “auth !== null”
}
}
}
The information in metaData can now be matched without a user being authenticated first. Of course, this can get more complex as you add more security but for easy understanding, this is it.
Upvotes: 0