Firebase verify multiple email addresses for the same user - firebase

I'm using Firebase web SDK 4.0.0 and want to enable my users to verify multiple email addresses for the same account. For context, my objective is to receive email from dave#home.com and dave#work.com and know that it's definitely coming from Dave (uid 123456789).
I've looked up the docs about linking accounts but I'm assuming this approach isn't going to work as I need multiple emails.
I thought about storing the emails in the db and linking them to the user but that doesn't hook into the Firebase verification process (which I want to use).
Any ideas of how to approach this would be very helpful.

If you want a user have multiple emails registered in his account. You have to do the linking in the firebase database. Below is how to implement the structure in the database.
{
"userAuth": {
"userId001": {
"userRNGId": "abc123",
"userEmail": "example01#gmail.com"
},
"userId002": {
"userRNGId": "abc123",
"userEmail": "example02#gmail.com"
}
},
"userList": {
"abc123": {
"userName": "James",
"occupation": "Programmer",
"userAccounts": {
"userId001": {
"userAuth": "userId001"
},
"userId002": {
"userAuth": "userId002"
}
}
}
}
}
With this structure you can still use firebase authentication to verify their email address.
userId001 and userId002 is the RNG created from firebase authentication.
Inside userRNGId(E.g abc123) you should create random user ID so that all the emails will be linked to that id.
I hope it helps.

Related

Hasura permissions question difference between admin and user

I am trying to figure out the difference between the admin role and the user role permissions when querying a Remote Schema, they both show that they have full access. However, when doing a query the user role cannot find one of the inputs for some reason. The query is
query SearchFacilities($getFacilitiesInput: GetFacilitiesInput!, $startDateInput: StartDateInput!) {
facilities(getFacilitiesInput: $getFacilitiesInput) {
facilityID
permitEntrances(startDateInput: $startDateInput) {
availability {
remaining
}
}
}
}
When running the query with the x-hasura-admin-secret it works fine. However, when I switch to the user role by setting a Bearer token for the user, I get the following error:
{
"errors": [
{
"extensions": {
"code": "validation-failed",
"path": "$.selectionSet.facilities.selectionSet.permitEntrances"
},
"message": "'permitEntrances' has no argument named 'startDateInput'"
}
]
}
They both have the same permissions according to the UI, in the remote schema section. Any ideas on what is causing this discrepancy? Been trying to figure this one out for a while, thanks for any help.

Firebase - Saving data

I have a question regarding the firebase.
I'm developing an app where there are three screens: the 'registration screen' where the user will create an account with email and password. The 'building profile screen', where the user will answer some questions to be implemented in his profile, (such as "What's your name?"). And finally the 'profile screen', where the user information will be displayed, such as the user name.
On the 'registration screen' I'm having no problem, the user fills in the email input and password input, and by clicking "create account", calling .createUserWithEmailAndPassword, the user account is created and it is taken to the 'building profile screen'. The question I'm having is in the 'building profile screen'. My question is: How can I save the user name and other data?
I read some articles on the subject but I had difficulty understanding. Can any of you guys help me with this?
You're going to want to create a node or multiple nodes in firebase for each user to hold their user-specific information. The database structure could be uniform like so:
users: {
uid_a: {
username: 'uid_as_username',
email: 'uid_as_email',
name: 'uid_as_name',
other_attribute: 'uid_as_other_attribute_value'
[,...]
},
uid_b: {
username: 'uid_bs_username',
email: 'uid_bs_email',
name: 'uid_bs_name',
other_attribute: 'uid_bs_other_attribute_value'
[,...]
}
[,...]
}
or split up like so:
usernames: {
uid_a: 'uid_as_username',
uid_b: 'uid_bs_username'
[,...]
},
emails: {
uid_a: 'uid_as_email',
uid_b: 'uid_bs_email'
[,...]
},
names: {
uid_a: 'uid_as_name',
uid_b: 'uid_bs_name'
[,...]
},
other_attribute: {
uid_a: 'uid_as_other_attribute_value',
uid_b: 'uid_bs_other_attribute_value'
[,...]
}
Which you choose is a design choice, but thats the idea.
Just complementing #Vincent answer, by default you can store the user name, email and photoUrl within firebase auth (read get user profile: https://firebase.google.com/docs/auth/web/manage-users).
If you need to store more info, like postal address, phonenumbers, and so on, you can create a node in your database like users and store all the data you need. You can even use the same UID created for auth as the ID of your database. This way it would be easier for you to get user infos in the future.
When you just create the user with email and password, you can return the user and add it to your database with a script like this
firebase.database.ref(`Users/${user.uid}`).set({
name: this.state.name,
email: this.state.email,
});
Consider the code above just as an example.
Prefer to use .set() instead of .push(). If you use .push() firebase will create a random id which you will not be able to change. Using .set() you can determine the value of your node.
Hope it helps.
This is taken from the official documentation that might give you clue how to update and fetch data from database.
Set up Firebase Realtime Database for Android
Connect your app to Firebase
Install the Firebase SDK. In the Firebase console, add your app to
your Firebase project. Add the Realtime Database to your app
Add the dependency for Firebase Realtime Database to your app-level
build.gradle file:
compile 'com.google.firebase:firebase-database:11.2.2'
Configure Firebase Database Rules
The Realtime Database provides a declarative rules language that
allows you to define how your data should be structured, how it should
be indexed, and when your data can be read from and written to. By
default, read and write access to your database is restricted so only
authenticated users can read or write data. To get started without
setting up Authentication, you can configure your rules for public
access. This does make your database open to anyone, even people not
using your app, so be sure to restrict your database again when you
set up authentication.
Write to your database
Retrieve an instance of your database using getInstance() and
reference the location you want to write to.
// Write a message to the database
FirebaseDatabase database = FirebaseDatabase.getInstance();
DatabaseReference myRef = database.getReference("message");
myRef.setValue("Hello, World!");
You can save a range of data types to the database this way, including
Java objects. When you save an object the responses from any getters
will be saved as children of this location.
Read from your database
To make your app data update in realtime, you should add a
ValueEventListener to the reference you just created.
The onDataChange() method in this class is triggered once when the
listener is attached and again every time the data changes, including
the children.
// Read from the database
myRef.addValueEventListener(new ValueEventListener() {
#Override
public void onDataChange(DataSnapshot dataSnapshot) {
// This method is called once with the initial value and again
// whenever data at this location is updated.
String value = dataSnapshot.getValue(String.class);
Log.d(TAG, "Value is: " + value);
}
#Override
public void onCancelled(DatabaseError error) {
// Failed to read value
Log.w(TAG, "Failed to read value.", error.toException());
}
});

Setting hierarchical rules in firebase by comparing array to an array in firebase security rules

I am making realtime chat of my app using firebase. The login is userId based. so the auth.uid is this userId. A user is owner of many profiles(say of his family members), and a profile can belong to multiple users(say a child profile can belong to his father and mother). Now a chat is always on behalf of a profile(i.e. a father and wife can send chatMessage on behalf of their son). I want to set security rules for this chat.
The issues which I am facing are
Only the users whose profile has created a chat-message can edit that message. I am unable to set this security as I would have to compare an array to an array for which I have to write a function in security rules which firebase does not allow.
Users:{
userIdOfVed:{
profiles:{
userProfileIdOfVedSon:{
profileId:userProfileIdOfVedSon,
relation:son
},
__:{...},
__:{...},
...
}
},
__:{...},
__:{...},
...
}
Profiles:{
userProfileIdOfVedSon:{
chats:{
chatRoom1Id:{
caseId:case32Id,
chatRoomId:chatRoom1Id
},
chatRoom3Id:{
caseId:case42Id,
chatRoomId:chatRoom3Id
}
}
//...Other user data(like email, phone no.) which might be required
},
__:{...},
__:{...},
...
}
ChatMetadata:{
chatRoom1Id:{
createdOn:ISODate("2017-04-13T11:25:35.668Z"),
members:{
userProfileIdOfVedSon:{
userProfileId:userProfileIdOfVedSon
},
__:{...},
__:{...},
...
},
users:{},//I want to avoid putting this field as least as possible, but if its very critical for setting security, then there is no avoiding it.
caseId:case32Id,
lastMessage:"hello world"
//...Other chat meta data(like last message,etc) which might be required
},
__:{...},
__:{...},
...
}
Chats:{
chatRoom1Id:{
message1Id:{ //these are randomly generated messageIds by firebase
userId:userIdOfVed,
userProfileId:1,
message:"hello world",
timestamp:1459361875337 //can be replaced by a standard date time format
},
message2Id:{...},
message3Id:{...}
},
chatRoom2Id:{
message34Id:{...},
message69Id:{...}
}
}
//Rules for reading the realtime database
//The list of profiles can be put in the payload of the auth token (auth.profiles) which is not implemented yet
Users:{
$userId:{ //A user can only read/write/modify his $userId key-value object
"./read": "$userId == auth.uid"
}
}
Profiles:{
$profileId:{ //Can be read/write/modified by Users who have access to this profiles.
".read": "root.child('Users').child(auth.uid).child('profiles').child($profileId).exists()"
}
}
ChatMetaData:{
$chatRoomId:{ //Only the profiles who are present in its "members" keys can read it and a profile can only modify his $profileId entry in "members".
".read": "data.child('users').child(auth.uid).exists()"
}
}
Chats:{
$chatRoomId:{ //Only the profiles who are present in "ChatMetadata.$chatRoodId.members" keys can read it and push new values in it.(optional: modification to a child can be done only if that profile belongs to "ChatMetadata.$chatRoodId.members" & his profileId==the child.profileId)
".read":"I AM UNABLE TO FIGURE OUT THIS RULE, AS FIREBASE DOES NOT ALLOW FUNCTIONS INSIDE THIS."
}
}
TL;DR: Can I compare array to an array in firebase security rules to set hierarchical rules

How to prevent malicious scripts writing to Firebase database?

I been reading firebase 3+ documentation for a while and I'm still wondering how to manage the following scenario regarding safety:
Let say I have a website for publishing local business like yellow pages in where everyone with an account can add new entries and edit the info of the existing ones with the following schema:
{
"businesses"": {
"62061635": {
"id": "62061635",
"name": "Cellphone store"
},
"66856728": {
"id": "66856728",
"name": "El Bambino restaurant"
}
}
}
If a user with a successful login write the following snipped in the developers console:
firebase.database().ref('/businesses/').once('value').then(function(snapshot) {
console.log(snapshot.val());
});
Practically all users could retrieve all the businesses info, that's not so drastic, but if instead of the above code the users use the following code:
var i=0;
while(i++ < 10) {
var id = generateRandomString();
firebase.database().ref('businesses/' + id).set({
id: id,
name: generateRandomString()
});
}
That's something I worry about, I know there are rules for database, but in this case where all users can add and edit the info, how can I prevent the users to run malicious scripts like the ones above?

How can i restrict access to my firebase so that only I - the owner can access it

I find my self very confused.
My task is very simple, i want to use Firebase with node.js so that only i will be able to access the base.
Usually services gives a sort of a key so that only the owner can login to the base.
Why isn't this possible? I don't need any authentication for users in my case, so i find the documentation very confusing since i don't need any authentication except for not allowing anyone else than me to access the base.
This is not supposed to be done via a 3rd party provider, this should be allowed directly from your service.
Please help.
Ok. so i managed to find the solution.
In you account you have the tab security rules which you should change to:
{
"rules": {
".read": false,
".write": false
}
}
Now go to the tab Secrets and you will find your auth key.
Now in the node.js code do:
var dataRef = new Firebase("https://<YOUR-FIREBASE>.firebaseio.com/");
// Log me in.
dataRef.auth(AUTH_TOKEN, function(error) {
if(error) {
console.log("Login Failed!", error);
} else {
console.log("Login Succeeded!");
}
});
This is confused me a little since they are talking about users, but i didn't think of my self (owner) as a user accessing the base.

Resources