Issue in using firebase.auth() in client side - firebase

I've a project in which a user needs to be signed in by using their email and password credentials.The user must submit his unique id(Roll number) along with email and password at the time of his account creation.
While doing the project, I've used firebase-auth on the login page to use firease.auth().onAuthStateChanged() function.But the issue here is anyone can create their accounts by simply running firebase.auth().createUserWithEmailAndPassword() function in the console without submitting unique id(Roll number).
Now how can I restrict the users from such actions and making them to submit their unique IDs for their account creation

You probably do not want users to have to submit their unique ids when creating an account. If you do require this, then you'll need to add a validator that pings a collection with stored IDs to make sure that the unique Id they are submitting is in fact unique.
Instead, let Firebase create a unique ID for the user and allow them to register by email password.
Once a user registers with the firebase.auth().createUserWithEmailAndPassword() method, if successful it returns an object with auth credentials. in that returned object is a user property that includes a uid key:value

Related

How do I allow a role insert into a table (for signup), but after that deny further inserts for that user?

That's my question. I am using Hasura, and defining 'user' permissions.
Users are of course allowed to modify their own information, and not allowed to insert new records into my users table.
But when they signup, they should be allowed to insert themselves. So how can I define this permission?
To make my scenario more clear:
I have a React app, that uses an external OpenID provider. So a new user signs up there, and the provider returns a JWT to my app, containing a user I've never seen before.
My app does not know that, it just uses the access token to send to the Hasura backend to retrieve further info about this user, using the 'user' role. But it uses a query which will automatically insert the user if not found.
There's really not a safe way to allow sign-ups without involving a backend service. It is a very bad idea to allow anonymous inserts into your user table, even if you added a unique constraint against a user ID or email address.
If you have the option of using NextJS, see the Hasura example for configuring NextAuth. This works by configuring your app with a protected API route that uses your Hasura app's ADMIN_SECRET to insert new users who have authenticated with a third-party.
If NextJS isn't an option, Hasura's Auth0 example similarly uses a callback method to insert an authenticated user if they don't exist.
In the user table, for the user role, you need to add a permission with custom check. And the check should be user_id equals x-hasura-user-id.
{"id":{"_eq":"x-hasura-user-id"}}
For non-logged-in users, leverage the anonymous role by setting the permissions that make sense for your use case: https://hasura.io/docs/1.0/graphql/manual/auth/authorization/common-roles-auth-examples.html#anonymous-not-logged-in-users
Edit after the comment:
Ah, I see. When the user comes to your app, your app goes and retrieves some data that it expects every user should have (for example perhaps the user info store on the user table). But since it's a new user, this info is not there.
At this point, your React app knows that:
there's someone with a legitimately signed JWT cookie (use a library to verify the signature) and
there's no user info from the backend. Therefore, the React app shows
a "Welcome new user, wait while we're setting up your account".
Then
the React app makes a mutation to a signup Hasura action you'll
prepare. Once that returns, you proceed as usually (redirect the user to their home page).
use hasura action handler instead. Inside your handler, do a check if the user already exists or not. If not then insert a new row.

About register user with firebase

Im triying to use firebase in my app but I have a doubt about registration process, I declared an User collection, but when I sign up with google or facebook, the data is stored in Authentication, I want create an user but besides the fiels email and password, also with a fields like address, role, city and use the createUserWithEmailAndPassword method , to create the user with all those fields, is there a way to do that?
Auth only creates it's own entry to its own table. so you should first get these details from the user and send them to user collection manually.
You can create a new user object adding all these details into it and call this:
this.fireStore.collection("users")
.doc(user.id)
.set(user);
Due to security reasons, I wouldn't recommend storing the password in the db though.

How to make auth.uid and database child key equal in firebase?

What's happening here is that I have an app where users just can register if they are invited. By existing users, they need to fill out a form with the invited user's data, and e-mail address. Then these data will uploaded to the firebase database, with an unique generated key by .push(). Then an email is sent by the app to the specified email address, with an unique registration URL. It looks like this: ${host}/register/?uid=${keyGeneratedByPush}. When the invited user clicks on the link, the browser will get the uid from the query string, and gets the data with it from the database. If everything goes well, the user clicks on submit and createUserWithEmailAndPassword() gets called. The problem is the next: the auth() will generate an unique id (uid), but I already have an existing user id (generated by push). What I want to make them the same then if an user logs in, I can get the user.uid, and get the data from the database with it. A possible solution can be to get all the users, loop through them, and find the email address get by the user object, but why if we have ids. So how to make the two ids the same?
You could create a custom authentication provider and use the push ID as your UID there.
But I recommend against doing that. I see the registration/invitation token in the invite as a different entity than the UID that you generate. While (depending on your use-case) there may be a 1:1 mapping between them, the values have different meanings. One identifies a specific invitation sent to a potential user, the other identifies a specific user.
I'd keep a list of the (pending) invitation tokens, and the email address they've been sent to. Then when the user clicks the link in the invitation, you can look up if it's the correct email address (if you care about that), and associate the eventual UID with the invitation code (if you care about that).

Why use UID in Firebase? Should I use it

I know UID is used because it is unique. But in my app, all of them are registered with Google ID, Google ID is also unique. Should I use UID?
yes it is better to use the uid.
From the docs:
You can let your users authenticate with Firebase using their Google Accounts by integrating Google Sign-In into your app.
So after you authenticate the users, the uid will be in the authentication page in firebase. That id will help you later in the firebase database also and it is easier to use and add in the database.
Can easily be gotten using this:
FirebaseUser user=FirebaseAuth.getInstance().getCurrentUser();
Then you can use the method getUid() to get the userid. So using it will make the work easier for you.
From the docs:
After a user signs in for the first time, a new user account is created and linked to the credentials—that is, the user name and password, phone number, or auth provider information—the user signed in with. This new account is stored as part of your Firebase project, and can be used to identify a user across every app in your project, regardless of how the user signs in.
Also check this link: https://firebase.google.com/docs/auth/android/google-signin (Next Step section)
I'll suggest you use email ID instead of UID because if the user account is deleted from your Firebase Auth (either you delete it using Admin SDK, or perform a manual deletion on console), the next time user signs in with the same email ID will now give you a different UID and therefore all of your data in your database which rely on your UID won't be accessible.
However, you can't use use an email ID as it is, because Firebase key doesn't allow you to use . (dot) as keys, so just replace your . with a ,. You can find more information here.
TL;DR
Use email ID as it will always be unique unlike UID which gets generated every time a user signs in if that ID was previously deleted on Firebase Authentication server.

In meteor how to prevent social logins from creating an account if one is not available?

Currently, by default if I try to use social login in meteor, it will create a new account for the user if one is not available. But I don't want that. Here's what I need :
When the user signup, I need to provide social signup options. When the user signup with the social account, it should come back to the app where I will present the user with a form to enter extra details. I don't want to create an account until those details are filled. I will pull the name and email from social accounts.
At login, if the user have already connected a social account, he will be allowed to login. Otherwise he have to signup first.
How can I implement this behavior in Meteor?
The way I handle this is in Account.validateNewUser
this function validates the user and returns true or false.
but you can add logic to the process.
In my case, I check if the user exists by email:
social logins (except for Twitter) all create a user with email.
the function contains a user object parameter with the user account info
If you do a check using Accounts.findUserByEmail(<email>) you can find if the user has been created previously.
In that case,
there are 2 cases:
user tried to create an account with password, just return true and the rest of the user create process will prompt the user that a user already exists with this email.
if it's a social login, I merge the 2 user objects to make it one, keeping the original _id. then return 'true' to pass the validation process.

Resources