Is there a way to automatically assign a User an ID in Firebase? IOS - swift

I am new to Firebase and I have been working within IOS to identify the users by an automatically generated key. Essentially I'm creating a leaderboard with highscores and levels. Instead of having the user sign up for an account I want them to already have an ID so they can just start playing and write their high scores to the leader board. At the moment I have this code:
let user = Auth.auth().currentUser
ref?.child("Highscore").child((user?.uid)!).setValue(highscoreArray)
For some reason I'm getting an error that the "user" is non-existant. Is there a way to automatically generate one without having to force the user to choose a username etc. Also I've tried childByAutoID and i keep getting new IDs within the simulator everytime I run it.
Thanks for the help.

Minimally, you have to put the user through a sign-in process. Auth.auth().currentUser won't return anything but null until that process is complete. There is no workaround for this requirement. The only way you get a uid is after the user signs in a creates an account.
If you don't want to user to have to do anything to sign in, you can enable and implement anonymous authentication to sign them in without requiring any input from them. You can then upgrade their account later in order to make it permanent, since anonymous accounts don't transfer between devices or survive an app uninstall.

Related

Firebase: Standard User Registration/Activation Workflow

I need to implement a standard user registration/activation workflow with Firebase. There doesn't seem to be an obvious way to implement this. When I say "standard", I mean how most email/password accounts work - not necessarily specific to Firebase. I'm sure you're familiar with this. This is the workflow:
User enters their username/password on a form with some validation and submits details
The back-end creates the user record in the database, but the account remains deactivated (i.e. user cannot authenticate - the activated flag is set to false)
The back-end sends an email to the user with a link to activate the account
The user clicks the link in their email which triggers activation. This is probably a Web API of some description.
At this point, the user record's activated flag ticks over to true, and the user can now authenticate
The link probably also has a deep link that opens the app or navigates to a web page
The user can now log into the app
How do I configure Firebase to do all this?
Currently, the app allows the user to register. I am using the Flutterfire SDK. I call createUserWithEmailAndPassword, which successfully creates the user in Firebase. But, the user is already activated. The user should have a state of "disabled" in firebase until the account becomes activated. I can't find any settings to default the user to disabled when the account is first created.
I also managed to get Firebase to send out an activation email by calling sendSignInLinkToEmail, but this call is really designed for email authentication - not email activation. Opening the link should activate the account, but I have not figured out how to do this. This documentation makes it sound like it is possible. Perhaps, the Flutterfire SDK is missing this? I don't want to allow people to log in without a password. I only want to use this call to send out an email.
What am I missing here? Is this non-standard behavior for Firebase? If so, why? If the user is allowed to use an app with an email address that is not activated, they can impersonate someone else. We need to confirm at least that they are custodians of the email address that they are claiming to have.
Do other Firebase people just not worry about this?
Lastly, I know I can achieve this by creating a collection for users in Firebase and putting an "activated" flag there. But, if I do that, I've got to write a cloud function that accepts the link and then updates the user in the collection based on the received link. But I thought this would be automatic in Firebase. If Firebase doesn't have this built-in, I have to put all the security over the top to stop users from authenticating when they have not yet activated their account.
This is a pretty valid concern. I suppose the way around this is to check whether the signed-in user is verified whenever the app is launched. The User object that is returned from Firebase Auth has an emailVerified flag. Check this page for more details.
Using this flag you can choose to show a different screen or pop-up that has a button to send a verification link to the registered email address. Until the user verifies this address, you can limit access to some of the app's screens if you want.
Please note that I have not checked if this emailVerified flag is true for sign ups using Federated login providers like Google Sign-in and Apple Sign In. You might want to check that out.

How to get a unique identifier for in app purchases in flutter which stays always the same

I'm using the in-app-purchase package for my Flutter app.
There is one non-consumable in app purchase in my app.
Each user creates a user account (using Firebase Authentication).
A user can be in a group with several other users who need to know if any of the other users have paid or not.
My idea was the following: After a successful purchase I wanted to store purchaseDetails.purchaseID in the database (using Firestore).
If the user then logs in to their user account on a different phone for example, they would not have to restore a purchase. Then I would already know that the user paid.
Additionally I would still implement a restore purchase button.
My problem is this: When I restore a purchase, I get a different PurchaseId than before. Even if I try to buy again (and the App Store tells me that I've already bought this item), I get a different PurchaseID afterwards.
So it would be possible for a user to create an account and buy the app. Then create a new account in my app and click on restore purchase. Then I have two accounts that are listed as paid in my database, although only one was paid for. You could repeat this as often as you like and give away the new accounts to family and friends for example.
Is there a possibility that I get the same ID every time? It doesn't have to be the PurchaseID. Maybe there is something else I could save instead (the app store userId?) or there is a completely different approach to solve my problem?
When I worked with subscriptions in the past, I used revenueCat. There it was possible to always get the same id from the same App Store or Play Store user to avoid this problematic. I could probably do that now too. But I would actually prefer not to use revenueCat if it is possible.
If you add the following import:
import 'package:in_app_purchase_storekit/in_app_purchase_storekit.dart';
it is possible to check if the purchaseDetails is an AppStorePurchaseDetails object.
Then you have the possibility to get the original purchaseID via the original transaction.
var purchaseID = purchaseDetails.purchaseID;
if (purchaseDetails is AppStorePurchaseDetails) {
final originalTransaction = purchaseDetails.skPaymentTransaction.originalTransaction;
if (originalTransaction != null) {
purchaseID = originalTransaction.transactionIdentifier;
}
}
With Google you always get the same purchaseID anyway. It is therefore not necessary to take any further steps here.
According to the documentation, you could also use the token (purchaseDetails.verificationData) instead of the PurchaseID as the ID or as a primary key.
purchaseToken is globally unique, so you can safely use this value as
a primary key in your database
You can also get additional information from Android by adding the following import:
import 'package:in_app_purchase_android/in_app_purchase_android.dart';
For example, you can check whether a subscription is automatically renewed.
if (purchaseDetails is GooglePlayPurchaseDetails) {
if (kDebugMode) print('isAutoRenewing: ${purchaseDetails.billingClientPurchase.isAutoRenewing}');
}

Is there any way to Firebase Auth twice in the same App instance?

Specifically this is for iOS but this could and WILL be relevant to an Android app as well.
I have an app in production use with a login portion that only loads if the user isn't auth'd. Now, I was wondering if I can have have 2 layers of this.
I'm currently checking if the currentUser is nil/null. If not, then I proceed. If so, I take the user to a login view.
I want to essentially have the user login 2 times if 2 layers are both signed out. But in this form:
UserA -> UserA-1
So if user isn't logged into UserA then they can't be logged into UserA-1, if that makes sense.
I'm not sure if Firebase has something already made to handle this or if I have to make my own. If the latter, i'm curious as to what approaches you guys have taken.
It's only possible to have a single user signed in at one time for one app instance. Signing in a second user will implicitly sign out the prior user.

Swift and Touch ID with Firebase

I was interested in adding the Touch ID option into my app. I have found many SO posts and other articles on how to implement it and how to handle errors. My question is if the user logs in, and then goes to the preferences VC and (if the device supports it) enables Touch ID....how do I retrieve the users email and password from Firebase...or store it?
I could be wrong, but I can't imagine Firebase would allow me to pull the user's password. So, would I just store the password from the log in VC in a constant and pass it from VC to VC just in case the user wants to enable Touch ID?
That doesn't seem like a great option either..
Edit
I want to clarify my question.
Initially in my app a user logs into the app using Firebase using an email and password. Later on if the user wants to he/she can enable Touch ID so instead of typing johnSmith#email.com and abc123 it knows on this phone that the user is johnSmith#email.com and the password is abc123.
My question is: How to I retrieve that users email and password? I do NOT have a child in my database with a list of emails and I DO NOT have a list of passwords.
The only thing I can think of to get the user is the following
let user = FIRAuth.auth()?.currentUser
But is that enough for a Touch ID log in? That is just a random string and not his/her email
And how do I get the password?
As long as Firebase doesnt support TouchId you will have to manage the username and password combination yourself. You will have to ask the user once for the username and password when he/she enables Touch Id and store the username/pw yourself.
The way to store sensitive information is by using Keychain, here is a sample project from Apple on how to do that.
Next time the user login gets confirmed by Touch Id you pull the username/pw from keychain and authenticate the user.

Can test users be verified? Can they have usernames?

I'm working on an app where I'd like to be able to do things with a user's Facebook username. I know that I can get this through the basic user object, but I'm worried about the case where the user doesn't have a FB username when they register with my site/application, but does gets one later. The question is how to test this with FB test users:
A user (a regular user, anyway) has to be verified before they can get a username. Is it possible to verify test users?
If so, is it then possible to give a test user a username?
Is it possible to change that username as part of the testing process (on the chance that my code doesn't work perfectly the first time :)?
What I'm thinking of doing is setting up a realtime subscription on "username", which I've established is possible. If the user above suddenly gets a username, my app gets notified and I can do whatever I do with it. But that implies that a lot of other things are possible, which they may not be. I could retrieve and check the user object on login and keep updating the fields, but I'd prefer to avoid that if possible. Any advice out there?
You cannot claim usernames for test users. You will have to use your own account or test with a real fake account, which Facebook frowns upon.