Firebase linking anon UID to email verification if verified on a different device - firebase

Has anyone managed to associate an authorised email to an anon UID that was created earlier on another device?
Here is the workflow:
User comes to the site for the first time, anon UID is created, they enter email as part of signup, which is added to their details in the db
An email is sent to them to verify the email.
However, user misses it for whatever reason.
Instead, they come again with a different device and try to log in using a password-less login by entering their email and receiving a link
they get the link and click on it. The email gets verified, but gets assigned to a NEW UID created on the 2nd visit.
The question is how can the email be linked to the 1st UID instead of the 2nd one on a new device?
Under 2, before the email is sent, I am calling firebase.auth().currentUser.updateEmail(email), but it doesn't seem to associate the email with the UID in the firebase for some reason. I can see that in the Firebase Authentication tab -- the UID is still showing as Identifier (anonymous). This is probably the root cause of the issue as otherwise the email would be there, just unauthenticated.
Any ideas would be welcome!

Setting an email address to an anonymous account doesn't change its provider to suddenly become email+password. It remains an anonymous account, it now just also has an email address associated with it. To associate the user with an email+password account, you'll have to sign them in with email+password credentials and then link those credentials to the existing anonymous account.
To link accounts/providers, you must create credentials for both providers on the same device and call the relevant API to link them.
Since you only have a UID from anonymous sign-in on the first device, that UID can't be recreated on the second device. And that means there is no way to link the email-link UID account on the second device to the anonymous UID on the first device.

Related

Firebase Authentication Provider for a User changed automatically to E-Mail. How to change back?

In a Firebase project, I have activated multiple sign-in methods (e-mail, Google, and Microsoft), which all work fine. I also have it activated to only allow one account per e-mail address.
The problem arises when a user successfully signs in via Google or Microsoft, then signs out and then signs in via e-mail, using the same e-mail address as before using Google or Microsoft. Then his account type changes to e-Mail and it seems like a no way back.
Is there a way to change user account types from e-mail back to Microsoft or Google?
Your code must have different functions written for different signin's. When the user first logs in, store his login method on firestore. You can get this from the signin function triggered or simply by the button user clicked. Then during each login add a check that if user exists and user's current signin method is not the same as the one stored on firestore, notify the user to use the correct one.
Or you can let the user signin using whatever they please but ultimately in your code, the function which is triggered will tell you the current signin method and you'd have the first/previous method stored. So you can do stuff accordingly.
What you are writing in question seams not how it works. When you sign in using Google provider your email is verified automatly and if you try to sign in using same email authentication will throw error that account with that email allredy exists.
If you created first account using email and password and didn't verify your email addres then if you sign in using google provider with same email address in it, email and password provider will gone because of was not verified and you wont be able to login using email end password unless you will setup a new password for this email.
If email was verified and you sign in using google provider with same email address. This provider will be added to providers array and you will be able to login using email and password and google provider.
To add multiple providers to your accaunt you can use linkWithPopup() function. If you created accound with diferent email address and want to be able to log in on this account with provider who has diferent email address for example.

Firebase anon user to be linked to an email

Would anyone know how we could implement the following with Firebase auth. Docs/searches haven't produced a good answer yet. So the use case is as follows:
User comes to a site to buy something. We allow them to buy without any sign-up barrier and on checkout, just ask them for their email. An anonymous user is created and their purchase is sent to their email provided.
With that email, we'd like to set up a passwordless account for them so that the user can log in later just with their email and see items bought in their dashboard. For that the anon uid recorded with the purchase needs to be associated with the email.
So the question is how to achieve that an anon account upgraded to a registered account with the email provided.
We've tried inserting a passwordless sign-in link sending at the point of the purchase, but it just created a new account with a new id, which is not what's needed. We need the uid to stay the same as the anon user's so that we can simply connect their purchases to the newly email-authenticated account. Perhaps, there is a way of associating an anon uid with an email before sending that passwordless signin link?
Hope this makes sense, but please do ask if anything is unclear.
To create a Credential object from an email link, you can use the EmailAuthProvider.credentialWithLink method. You can then use this credentials object to upgrade your anonymous account.
Also see: Deleting User account with using Passwordless Authentication?

Firebase - create a temporary user until the user signs up

I have a use case where User A can say that User B borrowed from User A some amount of money, similar to apps like Splitwise.
I'm using firestore to store the data. In this particular case, I'll store it as a document in the "Transactions" collection which will have the following fields:
amount: 20
fromUser: uid for User A
toUser: uid for User B
The issue here is that the User B doesn't exist yet and so there is no uid for the user B. What I want to do is to create a temporary user for User B with the email address which will generate a uid. And later when the User B signs up on the app, the same user is upgraded to a permanent user with whatever auth provider the User B has used.
While searching, I came across - https://www.freecodecamp.org/news/heres-what-i-wish-i-knew-before-i-started-using-firebase-9110d393e193/
Which mentions that this was possible with the firebase invites which is now depreciated. So, is there any other way to achieve this behavior now?
Firebase supports creating anonymous user accounts for just such scenarios.
Authenticate with Firebase Anonymously
You can use Firebase Authentication to create and use temporary anonymous accounts to authenticate with Firebase. These temporary anonymous accounts can be used to allow users who haven't yet signed up to your app to work with data protected by security rules. If an anonymous user decides to sign up to your app, you can link their sign-in credentials to the anonymous account so that they can continue to work with their protected data in future sessions.
Email Address of 2nd User Known
If you already have the email address for a user (User B) that has not yet signed up, then you can create their account using the Firebase Admin SDK.
See Create a user
The new User B email address could then be configured for Email Link Authentication by calling firebase.auth().sendSignInLinkToEmail(email, actionCodeSettings).
Since the User B account creation was initiated by User A, you would not be able to use Local Storage to save the email of User B to complete sign-in with the email link. However, this is not a problem, since as the documentation example shows, you may prompt the user for their email address.
if (firebase.auth().isSignInWithEmailLink(window.location.href)) {
// Additional state parameters can also be passed via URL.
// This can be used to continue the user's intended action before triggering
// the sign-in operation.
email = window.prompt('Please provide your email for confirmation');
// The client SDK will parse the code from the link for you.
firebase.auth().signInWithEmailLink(email, window.location.href)
...
Now that User B has successfully signed in using the email link, the standard process may be followed to Link Multiple Auth Providers.
The server side (aka Node.js) Admin SDK allows you to create users programatically. You would need some way to pin/stick the newly created user UID to userB. Email address would seem the easiest way. So UserA would need to specify the email address of userB, then you process that server side Admin SDK.
When user B signs in with their email address, Firebase Authentication will detect an existing account with userB's email address and throw an error which you can use to merge userB's account data.

Firebase: Securing records by email address when users can use fake addresses

I'm making a web app where you pay to use it first and then sign in. The sign up workflow is this:
Once a payment is made on my website, the client receives an order ID that is associated with their email address. The client sends this to a Firebase Function endpoint to activate their order.
The Firebase Function checks the order ID is valid and creates a Firebase user with a long random password (to prevent anyone from signing in), then sends a password reset email. A "payment" record is created in Firestore and associated with the user ID.
The user follows the password reset email then logs into my app. The paid features are activated if Firestore contains a payment associated with that user ID.
This all seems fine except:
A malicious user Bob could outside of my control creates a user for email "x#example.com" that he doesn't own and sign in using the Firebase client SDK.
Alice then makes a payment for her email "x#example.com".
Bob will still be signed in and can now use the features Alice paid for.
How do I prevent this?
One idea I had was the above Firebase Function could check if user "x#example.com" exists with an unverified email address and if so it would 1) delete that user and 2) create a user for that email address again (creating a new unique user ID). Bob would then have a different user ID than the one associated with the email address so couldn't access the payment record. However, this breaks if Alice makes two payments without validating her email after the first payment. What's a robust way of solving this?
Consider verifying the email before processing the transaction.
One option is to use sign in with email link. This will sign in the user and verify their email. You can also set a password after if you want. If an existing unverified provider is linked to the account, it will be unlinked and any existing session that a malicious user had previously set up will be revoked.

is it possible for users to choose any email at the time of password reset in frebase?

I am using ionic 3 and firebase for the backend.In my app I am trying to let users sign up with just username and password. Well firebase by default doesn't provide that option. So I am getting user's input as username (for example: 'mike123') then i add #myapp.com. so it looks like an email: 'mike123#myapp.com'. That is all fine, but a problem just came up when user's want to reset their passwords. Is it possible to let users type in any valid email address at the time they want to reset their password?.
You can change the password of the user by https://firebase.google.com/docs/auth/admin/manage-users#update_a_user. Note that this is in the Firebase Admin SDK, so will require that you run code in a trusted environment, such as a server you control or Cloud Functions.
But faking username+password by faking an email address is non-ideal. I'd consider creating a custom auth provider for your needs.
If the email provided when sending the Reset Password request doesn't exist for any user, then it will fail.
In Android, calling sendPasswordResetEmail with a non-existing email, it would return a:
FirebaseAuthInvalidUserException: There is no user record corresponding to this identifier. The user may have been deleted.
You should ask for a valid email from the user and save their preferred username separately upon the user creation.

Resources