Firebase user login managing connection with API - firebase

I'm quite new to firebase and I am looking for best practices using it, maybe I will be able to get some advices here.
What I want to do:
User login using firebase.
Problem:
I save user info in firebase but use SQL server as database where I need that user information as userId
Question: How should I approach that?
Register user on firebase and when I get response with userId and token, save it to my sql database too?
what's my current approach:
At this stage we're thinking of creating new users via admin panel (and then these users can sign in)
Would it be good approach to add user to sql database, send email to finish registration (create pasword) and then add this user to firebase, and with response send request to my backend where I update user that he's verified, add userId and token?

It's very common to store additional information about Firebase Authentication users in your own database. Whether it's good in your use-case is subjective, but it's definitely common.
Assuming that you have a server interacting with SQL server on the user's behalf, be sure to pass the ID token from the client to the server, decode it there, and then use the UID (and other claims) from that token in your database interactions. Don't allow the user to just pass their UID, as that'd be a security risk.
For more on this scenario, see the Firebase documentation on verifying a user through their ID token.
Your approach with an admin panel is a common first approach, but not something I'd recommend. Since you'll need to allow the user's to sign in with email/password, there is nothing keeping them from calling the createUserWithEmailAndPassword API themselves on your project. So I'd recommend leaving the creation completely to the clients, and save yourself from having to consider that an abuse scenario.
If you want to control what users an access the data, store a list of email addresses (since you seem to associate that with uniquely identifying a user already) in the database, and check the email address in the ID token is in the list (and is marked as verified in the token).

Related

Managing Session Cookies, from Firebase Authentication, with Redis

I am using Google Firebase Authentication to handle user management for my web application.
Specifically, I am using managed session cookies. The problem I am running into is figuring out how to associate each session with a corresponding user.
For example, I would have two separate tables:
User - Stores personal information such as name, email, password, etc
Account - Stores account related information such as posts, friends, etc
I was thinking of using Redis as a key-value store for this situation and the flow would work something along the lines of this:
User enters credentials
Credentials gets verified by Google's backend
User receives ID token
User sends ID token to my backend along with user id
Google's backend creates a session cookie
Backend would store the session along with the user id into Redis
Whenever user hits a protected endpoint that requires user id, a call to Redis would be made
I thought this might work because, within my Flask API, if I print out the type of the session cookie, the value is of type string.
I was wondering if this is an overkill, or if there is a better alternative to achieve what I want.
After much research and discussions with peers who work in the software industry, I have decided to use the strategy outlined in the question.
Feel free to comment if you have anything else to add.
Cheers.

Synchronize users created with Firebase Auth to my custom backend

I want to use Firebase Auth for my user login/registration process. Everything else should be handled by my own backend (spring boot app + postgres db).
Now I'm asking myself how I can synchronize a new created user to my user table in postgres. I thought about the following:
REST call through client - Everytime I get a success event from the firebase sdk I call an additional request to my backend which sends uid, username etc.
Problem: What if my backend call fails but the register process was successful ? That would lead to an inconsistent state since (at least thats what I understanded) I can't easily rollback. That would lead to situations where a user can login into my app without my backend knowing the user. This would crash/ invalidate all my following queries (e.g. search after user xyz would lead to no result even though he/she exists)
Check the existence of the user in the postgres database
Here I would query the uid from the database (which I got from the jwt) and create a new user if it doesn't exists in every incoming request.
Problem: The user query is a unnessecary overhead for every incoming request.
Trigger with cloud functions - When I understood it right firebase auth is firing events when a new user is created in cloud functions. This could be used to make the external api call.
Problem: I dont know what happens when my external rest call fails at this point. Can I rollback the registration ? Will I be ever catch this event again ? I also proably would have an eventual consistency situation, since I dont know when the cloud function triggers. Furthermore I would prefer not to include cloud functions to my stack
Is there any way how I could do this in a transactional manner ? Did anyone else tried is using sth simular ?
Thanks for every help!
The easiest way is actually to not synchronize auth data, but instead decode and verify the ID token of the user in your backend code.
This operation is (by design) stateless, although Firebase's own backend services often implement a cache of recently decoded tokens to speed up future calls with the same ID token.
Apparently, I finally came up with a different solution:
Register user per Firebase SDK (e.g. with email + pw method)
Make a post-call to my own registration api including the resulting uid from the previous step and some metadata
API creates a new user including a column with the UID + Fetches the firebase token of the user and adds an internal claim that references to the internal Postgres UUID via Admin SDK.
Frontend gets the created user and hard refreshes (very important, since the previously fetched token won't contain the newly added claim !) the firebase token and verifies that it contains the token. If it does -> everything is cool, if not some oopsie happened :) That will require a request retry.
Later when you start your app you can just check if the passed token contains the custom claim, if not open the sign up/sign in page.
Every endpoint except the one for registration should check if the claim is set. If not just forbid the request.
How to set custom claims:
https://firebase.google.com/docs/auth/admin/custom-claims#set_and_validate_custom_user_claims_via_the_admin_sdk
You can use the Firebase Admin SDK to create the user account from your back-end instead of from the client.
So first you create the user in your database, then grab the ID and use it to create a user with the same ID in Firebase.
If all goes well, send a confirmation to the client and sign it in using the same credentials they entered.
Why not creating an endpoint in your backend service and call this endpoint when a client side authentication succeeds?
This method should do 2 things:
decode token to get access to Firebase user object (Firebase Admin)
Compare Firebase user with your internal user table. if it doesn't exist you can create it using firebase user object, otherwise do nothing.
This solution allows you to do other nice things as well (Syncing user info between Firebase and your internal db, providing a way to let a frontend know if this user is new or not, ...) at a relative small cost (1 get call per sign in)

Do users need to create an account to read/write to Firebase

I'm making an app that has Firebase as its database. The app shouldn't need the user to create an account to use it, but I want the user to be able to read/write their data onto the database (so maybe they have to create an account?).
Do I have to make the users create an account in order to use Firebase?
My problem is that my security rules are read/write are allowed for everyone (which I know is wrong, but how do I change them and not need users to create an account?) Maybe that's the issue.
It is best to ask them to create an account
Although:
it can be a non-real email address and
there is anonymous auth also available
It sounds like you need the app to remember that user's particular data, so that when they return to the app, it is still their data (and not someone else's) that is being accessed.
To achieve that, we need each person's data to be stored in a different place in Firebase. Traditionally, this is by having them log in to some kind of system, most conveniently Firebase itself, and then the data stored in a branch of the database defined by their user Id.
Without logging in, you could simply ask the user for an identifier, such as "Bob" or "Carol", and then store their data under their identifier. The Firebase database would therefore have the following structure.
users/Bob/highScore: 3000
users/Bob/level: 7
users/Carol/highScore: 5050
users/Carol/level: 9
However this is not secure because there is nothing stopping Carol coming to the app and saying she is "Bob". Any such client-side activity you carry out to attempt to identify the user is not really authentication (in the opinion of Firebase) because all client-side activities can be faked relatively easily.
Firebase Authentication
The standard solution is to use Firebase to authenticate each user (see the Firebase authentication docs for this), and give your app a user Id (such as "8769dsg6f8g7698769876sdgs9") which is unique and known (by Firebase) to be correct.
Firebase security rules
You can then lock down the database using Firebase Security Rules so that only user 8769dsg6f8g7698769876sdgs9 can write to any of the users/8769dsg6f8g7698769876sdgs9/.... part of the database.
If you don't use Firebase to authenticate the user, Firebase will treat the user as unauthenticated and you will have no way to restrict each user to their own section of the database. Either you leave it wide open (to hackers etc!) or users will not be able to access their own personal data on it.
They can use a FAKE email address and password
If your concern is that they won't want to give out their real email address, you can ask them to make up any email address, e.g. mickeyMouse49857430679304#hotmail.com, and set a password. There is no obligation on your app to contact them on that email address or verify that the email address is correct.
Whenever they come back to the app, or access it on another device, they need to remember the fake email address and password.
Of course, if they lose their password, there is no way to reset it.
Anonymous Authentication, but at risk of losing access
The legendary Frank von Puffelen of Firebase, himself, has added a remark about Anonymous Authentication, in the comments below. From what I understand, this avoids them having to make up a fake email address.
I think the weakness of this is that if they lose their local web storage (e.g. if they manually wipe it, or move to another device), there is no way for them to re-access the same account, unless they have planned ahead by adding an email/pw to the anonymous account.
The only real way to have security per-user data storage is to use Firebase Auth to sign in the user, and write security rules to protect the database so that each user can only access their own data. There are no secure alternatives to this for Realtime Database.

Sharing user ID's as a way to find people

Is it safe to share a user's ID that Firebase creates when a new user is created? I'd like to use it as an easy way to find other people on my platform.
I don't see why it should not be safe, so if it is. Please enlighten me :)
I am not too familiar with your system or how Nintendo does this (not really a gamer) but you can build something like this:
You can display the list of users (using uid, displayName and photoURL which can be obtained using the Admin SDK or by a list you maintain in the Firebase Database, Firestore, etc) to an authenticated user.
Let's say that user wants to add a connection or friend, you can get that user's ID token, the friend's uid and then add that user's uid to that authenticated user's pending connection list after you verify their ID token.
On the other end, you want the other user to accept the connection request (assuming this how your people finder feature works in your app). You would show the list of pending requests. When the user accepts the request, they would send their ID token and once that's verified, you can consider the connection completed.
To summarize, you still need an ID token to confirm the user sending the request and the one confirming it. Otherwise, if you just solely rely on uids, any user can get the uid of other users and try to add them to each other's friends list, etc.
Hopefully this points you in the right direction.

Can I access the registration tokens of all users registered in my Firebase notifications?

Sometimes I want to send a message through Firebase notifications to one unique user, then I want access the token from that user, so I like to know what is the best practice for get that token at any time?
On initial startup of my app, the FCM SDK generates a registration token for the client app instance.
I can get that token, but if I save that token in Firebase realtime database, I think other people can access that data because it is "set persistent mode on" to access offline data.
My questions is:
Is it possible to get tokens of all users without save that in a database?
Can I get these tokens direct from Firebase Authentication? If not, what is the best practice for access these tokens?
I think other people can access that data because it is "set persistent mode on" to access offline data.
Simply save the registration token details to a secure node. Making sure that only you (or even including the user itself) to be the only ones that can access it. Read more on Understand Firebase Realtime Database Rules.
I can get that token, but if I save that token in Firebase realtime database, I think other people can access that data because it is "set persistent mode on" to access offline data.
Users won't be able to get the data they're not allowed to/wasn't designed to have on their device if you choose to restrict them.
Is it possible to get tokens of all users without save that in a database?
There is no API to get all the registration tokens related to your app. As mentioned in the documentation (emphasis mine):
After you've obtained the token, you can send it to your app server and store it using your preferred method. See the Instance ID API reference for full detail on the API.
It's the developer's (you) responsibility to send and store the registration token to a secure location.
Can I get these tokens direct from Firebase Authentication?
I'm not entirely sure what you mean by this. FCM Registration tokens are different from auth tokens. So, no.
If not, what is the best practice for access these tokens?
So long as you store the tokens in a secure location and make sure that you're always using the most recent/valid token, it should be good.

Resources