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)
Related
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).
I am using Firebase Auth for SMS login and I want to add to new users a custom "countryCode" claim to the token.
After the Android app validate the SMS code, it invoke the account service in my backend to create the new account and
in that step add the custom claim with Firebase Admin SDK.
The app need to do a force refresh token to get the new claim.
I need to know if after adding the "claim" the update is eventually consistent or not.
If it is eventually consistent I can't guarantee that the refreshed token have the new claim.
I'm not entirely sure what you mean by "eventually consistent" in this context, but you can be sure that these two situations are reliable:
After writing the claims successfully using the Firebase Admin SDK, an immediate call to re-read the claims using the SDK will return the same previously written claims.
A client token refresh that happens after a change to custom claims on the backend will result in the client seeing the new claims. You will need to make sure that the client doesn't refresh until the claims are successfully committed, so that there is no race condition. This could involve the backend signaling to the frontend by changing something in Realtime Database or Cloud Firestore to indicate to the listening client that it's time to refresh the claims. You could use a timestamp that indicates the time of the last write of claims for the user, and the client could compare that to the time it last refreshed.
We are using firebase auth and firebase auth UI to authenticate a user.
We want to disallow or block those user's, who is trying to use a temporary mailbox for signing up (eg: https://www.mailinator.com).
There are 2 proposed solutions:
Do a client-side validation for the email ID? (Difficult to manage a blacklist of email providers in the client. Also, people can still use API to hack it).
After the user signs up, on onCreate user event, we can trigger a firebase function to validate the email ID against the blacklist, then we can disable or revoke the account. But here,
if we are disabling the user, he/she will get access to our app for next 1 hour as the client already gained the ID token.
If we are revoking refresh token, we'll have to again wait for 1 hour or write the rule to make a query to Firestore to check if user access is revoked. (Better if we can avoid this query)
Is there a better or native way to solve this issue?
If we are not getting any other solutions, we'll choose to go with 2nd option (revoking refresh token).
I would do a combination of both solutions you proposed. Doing the client side check will trip up most people and for the more tech savvy that try to get around it, your onCreate trigger will deal with them.
You could also add their uid to a blocked list in the realtime database from your onCreate trigger.
Then you can listen to it on the client and log them out. And for database rules you can check if they are in the block list and so block the read/write rule.
a regularly updated service to check DPA is already being maintained.
Do a simple get request to:
https://open.kickbox.com/v1/disposable/{user_email}
this would return the response
{
"disposable": true
}
if email id is disposable.
you can send the get request with complete email id or just the domain.
e.g. https://open.kickbox.com/v1/disposable/jamond67#zdecaesgl.com
or https://open.kickbox.com/v1/disposable/zdecaesgl.com
I am using Firebase Web for a SaaS solution. My purpose is to have access to users' email at any time, either for sending notifications or triggering alerts from the backend.
For security reasons, Firebase auth does not allow to list users' email or to fetch emails based on user IDs. As a consequence, I keep a copy of the email into a specific collection in the Firebase database when a user account is created. The copy is made by a Cloud function that is triggered on user creation (following guidelines: https://firebase.google.com/docs/auth/extend-with-functions).
Thanks to the copy available in the Firebase database, I can access users' email. However, my issue is when a user changes his email.
Firebase auth provides the updateEmail function that returns a promise. I use this last to update the email in Firebase auth. Then, when the promise resolves I update the user email in the Firebase database. However, this has a major drawback: all the logic is performed on the client side and since both operations are not performed in a transaction if the client refreshes or closes his browser (or assume it crashes), then it is possible that Firebase auth is updated but not the Firebase database, thus leading to an inconsistent state.
I looked at the documentation, expecting the possibility to trigger a Cloud function when user auth information is updated. Unfortunately, I cannot find such a feature.
Another solution I thought about is to update the database from the Web client. Then, this last triggers a Cloud function that updates Firebase auth with the admin SDK. This last solution works but bypasses the check performed by updateEmail that ensures the new email is not used by another account. Also, the account hijacking protection performed by updateEmail is evicted, which is really bad from a security point of view.
Any idea to solve this problem properly is welcome.
Here are a couple of options:
When calling updateEmail, update the email in your database first before calling updateEmail. THowever, if an error occurs, you need to catch it and undo that change in your db.
When a user wants to updateEmail, send their id token and new email to your server or firebase function http endpoint. There you verify the ID token with the admin SDK, then use the client SDK require('firebase'), using the uid from the ID token, admin.auth().createCustomToken(uid), then using client SDK, firebase.auth().signInWithCustomToken(customToken). You can then call user.updateEmail(newEmail) on the backend and save the email.
Always save the uid only and just use Admin SDK admin.auth().getUser(uid) to look up the user and get their email. This guarantees you get the user's latest email as you will not be able to catch the email revocation if the user chooses to do so.
No need to save anything. Use the CLI SDK to download all your users and their emails. Check https://firebase.google.com/docs/cli/auth#authexport
This is also better as you will always be able to get the latest email per user even if they revoke the email change.
How can I create a firebase user from the node.js client? I see that there is a simple-login but that looks to be used from the web browser. I would like to authenticate with my firebase secret and then call the createuser api somehow.
The way my system is built the clients only send requests to the backend for processing. This way I have a log of every action taken by every user and I can guarantee that each alteration is applied to my other databases as well before it makes it into firebase. Also I do not want users to be able to create other users. Firebase is just a workqueue for me mostly but I am also using the simple login to verify the user then swapping them over to a login token afterwards to get the ability to check custom permissions in the auth on security rules.