Firebase - create a temporary user until the user signs up - firebase

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.

Related

Firebase subaccounts

I'm currently building a POS/Store admin app, when a user gets into my app, the Owner of the store will then be asked to login only once for setup purpose (e.g. a new machine), the app will then display a list of staffsName that has already been added by this owner, and then everytime a staff wants to start a new transaction, he/she will only need to click on his/her name, then enter his/her 4-digit pincode to 'login' and process the transaction.
How do i go about achieving this?
I was thinking of using firebase auth for the 'login' of the staff, but then when i log in using the staff credential, I will lose access to the uid of the owner, which is needed to access the owner's store data such as his/her products.
i'm also thinking of using firestore to store the 4digit pincode, but then i'm also concerned about security
There are multiple ways you can approach this, one where you utilize the email login by simply appending a fake domain to the username to create a valid email domain. This user account could be the designated 'user' in question, or utilize credentials inside custom claims or hidden in a database that allows the client or server (depending on your preference) to then log in as the user.
Moreover if you want the manager to login once you can add Authentication State Persistence to specify whether a signed in user should be indefinitely persisted until explicit sing out, page reload etc.
Another approach requires the user also to have a valid auth that is not an email password and you link your pin auth to that main account with Firebase Auth Linking per the documentation: https://firebase.google.com/docs/auth/web/account-linking.
This does however require that the user be registered from an auth provider such as Google, Twitter, Apple, etc. then the user will have to activate this link by logging in for authentication purposes. This can in theory be automatically generated and processed without the user knowing.
It is a long way around it since this is essentially a custom solution but it does create the flow you are looking for without having to use a custom auth provider.

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.

Firebase recover password transforms account type

we are building an angular 5 app with Firebase.
We allow users to login with email+password or google account and we don't allow to have multiple accounts related to the same email address.
We built a form to allow users to ask for a Password Reset Email if they forgot their email password credentials and works perfectly if the user has an email+password account.
The problem arises when the reset email is asked for a google account. We'd expect for firebase to throw an error, not allowing to send the email, but the email is sent and if the user proceeds resetting the email the account is transformed from google type to an email+password.
Is there a way to prevent this behaviour ?
There is no way to prevent this. When a user resets their password, they are making a conscious decision to do so. Firebase is providing a way to recover an email account, in case it was hijacked. In the process all providers are unlinked and a password is set on the account.
You have a way to check if the email is associated with google provider or not. Checkout the fetchSignInMethodsForEmail and fetchProvidersForEmail APIs. These APIs would return the array of sign in methods or providers associated with an email.

What does this firebase documentation mean?

Convert an anonymous account to a permanent account
When an anonymous user signs up to your app, you might want to allow
them to continue their work with their new account—for example, you
might want to make the items the user added to their shopping cart
before they signed up available in their new account's shopping cart.
To do so, complete the following steps:
When the user signs up, complete the sign-in flow for the user's authentication provider up to, but not including, calling one of the
methods. For example, get the user's Google ID token, Facebook access
token, or email address and password.
Get an for the new authentication provider:
Pass the object to the sign-in user's method:
If the call to succeeds, the user's new account can access the anonymous account's Firebase data.
What does this mean as in what code is actually required (specifically to link an email/password to an anonymous account)? Note the above quoted text is quoted accurately.
I've tried this code but it does not work as expected:
firebase::auth::Auth* Auth = firebase::auth::Auth::GetAuth(App);
firebase::auth::User* User = Auth->current_user();
firebase::Future<firebase::auth::User*> Future =
User->is_anonymous() ?
User->LinkWithCredential(firebase::auth::EmailAuthProvider::GetCredential(email, password)) :
auth->CreateUserWithEmailAndPassword(email, password);

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