iOS firebase auth current user get nil when restart app - ios

Auth.auth().signIn(withEmail:
In my case, When I first time open app and sign in firebase account like above code
then I reopen app
let user = Auth.auth().currentUser
user is not nil and then I reopen app get currentUser again user is nil that mean I did not sign in
I have the other app do like this, but the user always not nil.
I wonder why this happens.

Firebase automatically restores the authenticated user when the app restarts. But this requires a call to the servers, which may take some time. If you check Auth.auth().currentUser while the check is still in progress, you will get nil as the result.
To ensure you get the value once this initial check is done, use an auth state listener as shown in the first snippet in the documentation on getting the current user. From there:
Auth.auth().addStateDidChangeListener { auth, user in
// ...
}
Once this listener fires for the first time:
either the user variable will have a value if the user authentication state could be restored,
or it is nil if the user was not signed in last time the app ran, or the authentication state couldn't be restored (for example, because the account is disabled, or the password was changed).

I think it a big possibility you might be signed in on another device or signed in a different profile and didn't know, you might have some sync problems or security issues that did a safety measurement until you fix the security issue

Related

What is the reason to save Firebase authVerificationID?

When logging a user in or signing the user up for the first time and using phone auth it says:
Save the verification ID and restore it when your app loads. By doing
so, you can ensure that you still have a valid verification ID if your
app is terminated before the user completes the sign-in flow (for
example, while switching to the SMS app).
I'm not exactly sure what is the purpose of saving it.
0- the user opens the app and they are on the Login screen
1- the user adds their phone number (below)
2- the callback receives the authVerificationID
3- before the user is taken to the SMS screen, the app is somehow terminated
4- when the user opens the app again, because they haven't logged in yet, they are right back on the Login screen. When they enter their phone number again, they receive either a brand new authVerificationID or the same one (I'm not sure), and they are taken to the SMS screen. Either way both are valid and will get them to the SMS screen.
What does saving the authVerificationID do when no matter what, if the app is terminated, they have to add their phone number again because they will be back on the Login screen?
If the answer is "check if the authVerificationID is saved, and if it is then bring them to the SMS screen instead of the Login screen" then that is bad ux. The user might come back an hour later, when they first open the app they will see the SMS screen and be confused.
PhoneAuthProvider.provider().verifyPhoneNumber(phoneNumber, uiDelegate: nil) { (verificationID, error) in
guard let verificationID = verificationID else { return }
UserDefaults.standard.set(verificationID, forKey: "authVerificationID") // how does this help me?
// A. take user to sms view controller
// B. use authVerificationID && verificationCode for sms sign-in
}
The answer is pretty much what you said - if the user leaves your app in the middle of the auth flow, you can you can resume the sign-in flow from where they left off - i.e. the SMS verification step.
Once the user leaves your app, you have no guarantees that your app will not be terminated. It depends entirely on the OS. So your user might end up in a cycle where they just can't complete the sign-up (however unlikely this case is).
As for bad UX comment - it's very subjective (and depends on your design), and also time-dependent.

persistence with Firebase and swift 4 [duplicate]

This question already has answers here:
How to maintain user session after exiting app in Firebase
(2 answers)
Closed 2 years ago.
I have been looking around for some ways to have my app remember that a user is signed in but could find solutions for Firebase 3. I can login just fine with Firebase authentication but when I quit the app it takes me again to the login. This is closest solution I feel like I have. code snippet
This is what I followed from a youtube tutorial.
Thanks!
You stay logged in with firebase authentication, there's no need to try and re-login users. As long as the user doesn't log out, even if he kills the app, the next time he uses the app, he's automatically logged in. If you want to check if a user is logged in or not, this line of code will get you what you want:
let loggedIn = Auth.auth().currentUser == nil
if loggedIn is true then don't go to login page
If you want to listen to the authentication state of a user, just add an auth state listener after firebase configuration in AppDeledate like so:
FirebaseApp.configure()
Auth.auth().addStateDidChangeListener { (auth, user) in
if let currentUser = user {
// Do something with the current user, for example, fetch user info
// Suppose you have a "users" table in your database and each
// user is distinguished by their 'uid' property, then
Database.database().reference()
.child("users/currentUser.uid")
.observe(.value, with: { snapshot in ... })
}
}
Whenever the auth state changes, this code will be executed
BTW, this auth state listener is very helpful when you want to re-render some screens whenever the auth state changes. You can post a notification in the code above using NotificationCenter.default.post(...), and receive the notifications in your view controllers

Firebase Authorization Weird State after 24 Hours

I understand that by default Firebase invalidates a login token after 24 hours. However, I am finding the behavior strange after this time period. When the app is run it checks to see if the user is logged in and if so it goes into the app otherwise it stays on the login screen:
if self.ref.authData != nil
{
self.performSegueWithIdentifier("mainTabSegue", sender: self)
}
This works fine unless the token has expired after 24 hours. What will happen then is that the app will still see that authData is not nil and it will send it to the next VC. The next VC makes uses of the UID which then causes the app to crash. Running the app again will then show that authData is in fact nil and the user will be asked to login as is expected.
So the question is why, after the 24 hour period, is authData not nil when the user is clearly not logged in? The Firebase documentation seems to indicate that checking authData as above is the correct way to determine whether a user is logged in.
Before your segue if you extract the uid from authData then you can pass that user to the first view controller. If you pass the user object to your first VC constructed in the App Delegate, then your app won't crash. I vaguely remember something similar happening to my app (i.e. where it thinks the user is logged in but then changes back to login). I'm not sure why this happened but it's possible the app tried to start where it left off?
You can also change the token expiration length on Firebase, as you may know.

What is the equivalent of iOS applicationWillTerminate in IBM MobileFirst Hybrid app?

Scenario:
I want to call the logout function if the app is terminated. I'm able to do it using native code:
- (void)applicationWillTerminate:(UIApplication *)app
{
// Run Logout function
}
Problem:
How to do it in IBM mobilefirst hybrid app?
// ************************************************
Edited
First of all, user login in to the app, if the user key in the correct user id and password, it will add the userIdentity into "loginRealm".
WL.Server.setActiveUser("loginRealm", userIdentity);
Next, user closes the apps without logout. So, when the user login for the another time, MFP server will not return any feedback since it will hit this exception:
Cannot change identity of an already logged in user in realm
'loginRealm'. The application must logout first.
Hence, I have to logout the user from MFP server by setting the "loginRealm" to null in adapter;
WL.Server.setActiveUser("loginRealm", null);
The above line of code is in the logout function defined in authentication-config.xml.
The client side device runs this line of code and it will trigger the logout function. Besides, it will reload the App upon success:
WL.Client.logout('loginRealm', {
onSuccess: WL.Client.reloadApp
});
Steps that I've tried:
1) At WlcommonInit() I added WL.Client.updateUserInfo(); and if WL.Client.isUserAuthenticated("loginRealm") return true I will logout the user from server. However, WL.Client.isUserAuthenticated("loginRealm") will always return false. This is because, it needs to take sometime around (30seconds to 2 minutes) for the flag to turn true after WL.Client.updateUserInfo();. So my login still fail and hit the same error.
2) I tried to logout the users during the user click login button. But the app will refresh and return to login page again due to reloadApp. The logout code I get from IBM mobilefirst website. So user need to click and type 2 times in order to login into the main menu.
WL.Client.logout('loginRealm', {
onSuccess: WL.Client.reloadApp
});
Am I doing it wrongly? Or are there any other methods to get WL.Client.isUserAuthenticated("loginRealm") return true instantly after WL.Client.updateUserInfo(); ? Can we remove the reload app line of code in logout function?
I don't think this is doable, because that logout function (in MFP) will require server connectivity (request and response) and if the app is by then killed, I think it's going to cause unpredictable results.
Note though that it seems to be not recommended to use that function anyway? applicationWillTerminate when is it called and when not
What you should do perhaps in order to simulate it, is to logout-on-login, so that it would appear that the app is logged out when opening it. You can extend the duration of the splash screen so that the end-user will not see that s/he is logged in (in case the session was still alive between the closing and re-opening of the app), until really logged out and then you can display the login screen again or any other required screen.

ubiquityIdentityToken vs. CKContainer accountStatusWithCompletionHandler

Which method is better to decide which user is logged in?
let ubiquityIdentityToken = NSFileManager.defaultManager().ubiquityIdentityToken
returns a token, and client can compare wether it is the same than last time. The advantage that it returns token if device is offline too.
accountStatusWithCompletionHandler returns only a status value, but not an ID or token about who is logged in. So in offline mode it is useless.
Am I right?
My other problem, that sometimes even user is logged in and online ubiquityIdentityToken returns nil.
How do you retrieve user ID at launch?
If you're using CloudKit then the CKContainer accountStatusWithCompletionHandler method is how you should check whether the user is logged into iCloud or not (supported since iOS 8.0). The CloudKit Quick Start shows an example of how to use it.
fetchUserRecordIDWithCompletionHandler is how you should get the user's record ID, which is scoped to that CloudKit container but the same for that iCloud account across devices.
In iOS 9.0, you'll also have CKAccountChangeNotification, which will notify your app when the iCloud status on the device changes.

Resources