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.
Related
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 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:
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.
In Meteor, how can I proceed with LoginWithService (or LinkWithService) and get the service data without actually creating an account?
In my app, I use the service API keys to do certain tasks, to do that I use LinkWithService()
But I also allow users to login/create accounts with LoginWithService() function. But these two functions conflict with each other because if an account already exists with password + service, it will force a log out followed by another log-in.
I'm not sure if that made sense, anyhow I would like to just get the login service data without actually creating an account. How can I do this?
So I'm building out an app with Meteor and noticed when I log in with Twitter and then Facebook, I create two separate user accounts. Is there any built in way to make sure these are merged? I'm not seeing any email address in the twitter based user account, so I can see it might be difficult to figure out which accounts to link.
Suggestions? Thanks!
I've been in a similar situation so here's a good starting point for you:
You might want to do the merge at the Accounts.onCreateUser event. Basically, what you would do at this time is to:
Do a mandatory protocol / routine to save the email in some profile field in any authentication method as much as possible, so that you are able to do the next step, which is..
Whenever another authentication method is used (to create the user), you can compare the existing database of users (now confident that an email field would be present at all times to check against), and do the merge whenever an exact email match happens.
It's a shame I do not have the code now because I tried this protocol once, but I quickly decided that I'll just stick with one authentication method for some reason. Maybe I'll update this answer when I can get around to try and code that again.. or maybe not.