I have my app set up so that users can use it without logging in. This includes being able to save data. Each device/browser tuple generates a new anonymous user account for storing data.
I'm in the process of adding (facebook) login so that users can make sure their data persists across browsers and devices.
The firebase documentation shows how to handle a case where a user tries to link their account from multiple anonymous accounts and recommends an approach for merging data:
https://firebase.google.com/docs/auth/web/account-linking
My problem with this approach is that it deletes the original account that was linked which essentially boots the first account out of it's logged in state.
Imagine this flow for a single user:
Logs into device A & saves data
Logs into device B & saves more data.
On device A begins "login" flow using facebook for and ends up linking facebook credentials.
On device B they login/link facebook again (linking fails so we must use an alternate method for recourse).
The process recommended deletes the original account generated on device A & they must log in using facebook again on this device.
I've implemented a different process which doesn't result in device A being booted, and instead logs device B into the account generated on device A. My problem with this flow is that I can't delete the user data from device B once I've successfully logged in to device A because I'm using access control rules on firebase so that user data may only be modified by the logged-in user who it belongs to.
potential (suboptimal) solutions:
Delete the user data before logging into the other account but then if it fails at any point user data is lost.
Upon successful login to account A I could then log out, log into account B, delete B's data and then log back in to account A but this solution seems very inelegant.
I'm confused as to why the example in firebase docs seems to have this glaring issue and wondering what the best practice for this situation is.
I got no responses, but I implemented what I find to be an "elegant enough" solution to the problem.
Instead of deleting the prevUser's account & data after succesful login to the other account, I just delete the account:
I implemented a firebase function to handle the deletion of the orphaned user data:
Related
My team is using Firebase Auth in our project. We're using custom claims to properly authenticate whether or not a user has access to a specific piece of information. We're storing each piece of information and deciding access for the user based off whether or not the user has access to a specific location. Each piece of data is somehow associated with a location, and we are storing the location id in the custom claims for the ID Token.
The problem is that a user potentially has access to thousands of locations. Instead of storing thousands of locations in the custom claims, we think it's better to generate a new custom token and exchange it for a fresh id token every time the user switches locations. That means that it's potentially reasonable for a user to generate a new custom token every few seconds as they switch through their locations if they are doing it quickly enough.
The Firebase Auth documentation doesn't indicate anything in regards to any rate limiting in this regard.
Are we going to run into any issues / rate limiting if a user switches through their locations very quickly? This would be unusual, but I just want to make sure that the worst case will still work.
The control of Firebase Authentication custom claims is an Admin SDK operation and as such is not subject to rate-limiting. Firebase Authentication as a whole is designed to handle millions of concurrent users and is subject to various rate limits. Updating a user's custom claims would only contribute to the overall limits of 1000ops/sec and 10 million ops/day (at time of writing).
However, custom claims should be used for access control related data that will infrequently change such as the name of a role or a building ID. This is because the propagation of changed custom claims can take up to an hour and requires that the client code manually refresh their tokens after any changes to see an immediate effect. Custom claims have no mechanism to notify clients that they have been updated.
I'd reconsider your approach and store the list of locations a particular user has access to in the Realtime Database or Cloud Firestore rather than the ID token itself. You can then use this information to secure their access using appropriate Security Rules for those databases based on their user ID. By configuring a listener to that portion of the database, your client code can be instantly notified when a user gains or loses access to a new location. Additionally, you can poll information from multiple locations at once so you can show information in a notification feed or dashboard - something that can't be done with the claims strategy.
In my Firebase web app, I offer 3 different authentication methods – phone, email/password, and Google.
When new users go through the FirebaseUI sign-in flow, sometimes they don't remember which method they signed up with originally and use a different method (which creates a new user). For example, they created an account originally using their phone number, but when they return later (unauthenticated, perhaps on a new device), they see "Sign in with Google" and try that option – which creates a brand new user/account.
They are then confused why their account state is blank/new.
Is there a way to define a sign-in flow as such, so that if a user does not exist, it should not create a duplicate account (or at least offer an option to link to an existing user)?
I'm using the FirebaseUI for simplicity and hoping there's a flag or something I can set in the config that will achieve this.
For example, they created an account originally using their phone number, but when they return later (unauthenticated, perhaps on a new device), they see "Sign in with Google" and try that option – which creates a brand new user/account.
That's normal behavior since you don't have any information that it is the same user. To solve this, you should collect the email address of the user first time he/she signs up with the phone number. In this way, you can check the second time, whether the user has already an account in your app by searching for the existence of the email, as explained in my answers from the following posts. That's for the Realtime Database:
Checking if a particular value exists in the Firebase database
And that's for Firestore:
Firestore query - checking if username already exists
Is there a way to define a sign-in flow as such, so that if a user does not exist, it should not create a duplicate account (or at least offer an option to link to an existing user)?
Yes, by getting specific data to recognize the user. You either get the email address, as explained above or you get the phone number if it tries to sign in the first time with Google.
I am building a job portal for the web using React, Redux and Firebase/Firestore. I've completed all the features I needed except one.
I want unregistered-users/job-seekers to be able to:
Bookmark job posts.
Keep the record of applied jobs.
Keep the record of search queries.
I am thinking about using IndexedDB for this feature. Particularly Dexie.js to make things easier. However, this data will be persisted in user's browser and user will have no access to it in another browser or device. Therefore, I want to give users an option to be able to save all the data to Firestore if user sign into the website and I need this to be automatic. So, as soon as user signs in, I will save it to the database.
I thought about using Anonymous Authentication instead of IndexedDB/Firestore, so all the data will be saved into the database and as soon as user signs in using credentials, the user can claim the ownership of the data. However, this is an extra step to use these features I listed above and not everyone is happy with authenticating an app even though nothing is required from the user. Besides, there will be so many ghost accounts.
So, as I mentioned in the title; I want to save everything to IndexedDB (I will take care of this), but how am I going to synchronize all the data in IndexedDB to Firestore as soon as user signs in?
I imagined the basic process will be like this:
User clicks "Bookmark Job Post"
App checks if users is authenticated or not.
If authenticated, save the bookmark to the Firestore.
If not authenticated, save the bookmark to the IndexedDB.
If User decided to sign in or sign up, check IndexedDB and synchronize it with Firestore and clear IndexedDB.
How can I achieve the 5th step technically? Is there any built in system in Firebase? Also, please feel free to share your idea if you can think of another way implementing this feature. Should I be using firebase.auth().onAuthStateChanged() for the 5th step?
And lastly, how should I structure the Firestore to save bookmarked jobs, applied jobs and search history?
Should I create a bookmarkedJobs collection and have documents of jobPosts duplicated for each user, who bookmarked the job post? And every time a job post is updated by an employer, I will have a cloud function going through bookmarkedJobs collection, updating every instance of it?
Thank you
This may be of interest to you
https://dexie.org/docs/Syncable/Dexie.Syncable.js
Been looking into making my website fully static/pwa, and just using indexeddb, and some webservice for data handling/storage ..this seems like a interesting route to explore.
I want to know what will happen to the users of my app that I used anonymous sign in method for them.
The Firebase documentation is really BAD and didn't explain everything and expect developer to find out himself.
I found in its old version documentation that anonymous session will expires based on the expiration time has been set in Login & Auth tab, but even there didn't mention this means just the session ends or it means that user id will remove also from my app users list or what EXACTLY happened?
I found this answer but it really is not acceptable. The number of anonymous users will grow very very fast if you do a web app and make every thing hard.
I even cannot see the number of my app users in my dashboard!!!!!
So, what should i do? should i develop a dashboard for my data myself or Firebase team should do it? At least for managing users i should have more power than just searching user with their email and when you use custom login you cannot do this also.
Anonymous users don't expire, and there isn't currently any automated way to purge them.
Firebase doesn't automatically remove them because it doesn't really know if a user is still storing data linked to that login - only the app creator does. Imagine if you are playing a puzzle game on your phone, and get to level 100. Then when you go to play level 101 next year, all progress is lost. Firebase can't just assume a user being inactive for a year means that the account can be removed.
There is a couple tools that should help, though.
1) Admin SDK & Firebase CLI list users.
2) Linking multiple auth providers
3) Auth State Persistence
Once you list your users, you can check that each doesn't have any other providers, and hasn't been used recently, doesn't have data stored, and delete them.
Better, though, would be to ensure that only one account is created per user. If you create an anonymous account to help users store data before logging in, you may want to consider prompting them to link a auth provider (like Google or email). If you link the account, rather than creating a new one, you'll avoid abandoned accounts from active users.
In general, you will also want to make sure to use auth state persistence to ensure that there aren't more accounts than necessary being created. Creating 1 account per new visitor, rather than 1 per time someone repeatedly visits your page, will significantly help keep user growth in check.
In my case, I am using the anonymous sign-in method for authentication without the knowledge of the user.
Each time when the user leaves the app, delete the anonymous user by -
FirebaseAuth.getinstance().currentuser?.delete()
There will be no stacking up of anonymous user with this and limits the number of anonymous user in the app
2023 update
Firebase has automatic clean up now.
If you've upgraded your project to Firebase
Authentication with Identity Platform, you can enable automatic
clean-up in the Firebase console. When you enable this feature you
allow, Firebase to automatically delete anonymous accounts older than
30 days. In projects with automatic clean-up enabled, anonymous
authentication will not count toward usage limits or billing quotas.
Any anonymous accounts created after enabling automatic clean-up might
be automatically deleted any time after 30 days post-creation.
Anonymous accounts created before enabling automatic clean-up will be
eligible for automatic deletion starting 30 days after enabling
automatic clean-up. If you turn automatic clean-up off, any anonymous
accounts scheduled to be deleted will remain scheduled to be deleted.
These accounts do not count toward usage limits or billing quotas. If
you "upgrade" an anonymous account by linking it to any sign-in
method, the account will not get automatically deleted. If you want to
see how many users will be affected before you enable this feature,
and you've upgraded your project to Firebase Authentication with
Identity Platform, you can filter by is_anon in Cloud Logging.
Docs
There is a possible cloud function for that.
Check: delete-unused-accounts-cron
This function deletes unused accounts after a certain time. Which might be also helpfull for nonanonymous users.
If you only want to delete anonymous users or check only for them (for example delete after a different inactive time than normal users) you can identify them by checking:
const inactiveUsers = result.users.filter(
user => {
isAnonymous = user.providerData.length == 0;
//do something when anonymous
});
If you'd like anonymous users to be removed from your user list, you'll have to write a service to do that for you.
Since firebase doesn't provide a way to list registered users, you'll have to make sure you're storing some sort of user list in the database. You can then use the node.js admin sdk to get user data, check if the user is anonymous, and find when the user was created. For performance reasons, you may wish to store this information in a special area of your database and retrieve it all at once. Once you've identified a stale anonymous user they can be easily deleted.
I'd like people to be able to initially use a meteor app without explicitly creating an account until such time as they wished to share their data or see their data on another device. Even when they were happy to explicitly create an account, I'd like the option for that user account to be passwordless (i.e. https://passwordless.net/).
But I'm struggling at the first hurdle. How do I check that a user account doesnt already exist and create one if necessary?
There are a few packages which look promising:
https://github.com/artwells/meteor-accounts-guest/
https://github.com/tmeasday/meteor-accounts-anonymous
If neither of those are exactly what you want then they should at least provide a good starting point.
An alternate would be to use accounts-password and automatically create a unique user account for the guest once they perform some important action so you can store their data. Store the login credentials for that account in localStorage (or a cookie). Then once they are ready to signup, move their data from their temp account to their real account and delete the temp one.