Logout on Facebook's Firebase - swift

This question is asked before:
Firebase sign out not working in Swift
Logging a user out with Firebase 3 and Swift still shows the `currentUser`
Firebase - iOS Swift: FIRAuth.auth().signOut() not signing out current user
However all the answers are not working for me. I have VC 1 where the user can login, and in the viewdidappear I have a print that prints the user?.uid. In VC 2 I have a button that should logout the user and goes back to VC 1. The code in VC 2:
#IBAction func logOut(_ sender: UIButton) {
if FIRAuth.auth()?.currentUser != nil {
do {
try! FIRAuth.auth()!.signOut()
} catch let error as NSError {
print(error.localizedDescription)
}
}
FBSDKAccessToken.setCurrent(nil)
loggedIn = false
storedValuesData.setValue(nil, forKey: "savedLoginEmail")
storedValuesData.setValue(nil, forKey: "savedLoginPassword")
jumpToVC1()
}
When I am back at VC 1, when the user pressed the logout button, the print prints again the user's UID. But that user should be logged out, therefore the print should be nil. How can I make sure VC 1 only gets presented when I am sure the user is logged out? I thought completion blocks would be nice, but I am not sure how that would work here...

You don't need completion blocks, as the method is synchronous.
#IBAction func logOut(_ sender: UIButton) {
guard FIRAuth.auth()?.currentUser != nil else {
return
}
do {
try FIRAuth.auth()?.signOut()
FBSDKAccessToken.setCurrent(nil)
loggedIn = false
storedValuesData.setValue(nil, forKey: "savedLoginEmail")
storedValuesData.setValue(nil, forKey: "savedLoginPassword")
jumpToVC1()
} catch let error as NSError {
print(error.localizedDescription)
}
}

AccessToken.current=nil is worked.Because logout is not reverse it.
do {
try Auth.auth().signOut()
AccessToken.current=nil
return true
} catch {
return false
}

Related

Firebase not storing logged in user

Was working with Firebase for almost half year now and never had this issue. Using code just like before to create new user, he shows up in console, when i close app i can sign in but using same code as always it keeps prompting me for password. In first VC i have:
if let user = Auth.auth().currentUser {
performSegue(withIdentifier: "authorized", sender: self)
}
Which will check if there is auth token stored and perform segue to loading screen. However this never happens. The code is ran but doesn't do anything, no errors in compiler and no errors in console.
EDIT 1: also tried to create new project where i rewrote all the code getting same result, but my other project works without any issues, also i'm able to do anything else besides this using firebase such as access Firestore just not storing the user, went over all the documentation but couldn't find any solution.
EDIT 2: sign in code
if(email.text != "" && password.text != ""){
Auth.auth().signIn(withEmail: email.text!, password: password.text!) { user, error in
if(error == nil && user != nil) {
userID = (Auth.auth().currentUser?.uid)!
print("Signed in as: \(userID)")
self.performSegue(withIdentifier: "load", sender: self)
} else {
print("Error found: \(error?.localizedDescription)")
}
}
}
Solution:
DispatchQueue.main.async(){
if let user = Auth.auth().currentUser {
userID = (Auth.auth().currentUser?.uid)!
self.performSegue(withIdentifier: "authorized", sender: self)
}
}
Loaded with async so firebase will configure before checking for auth
The issue is likely that you are calling your code before firebase has properly initialized. I recommend using the entry view controller's viewDidAppear for things such as these. If you were using viewDidLoad, it is likely that firebase did not load yet.

Firebase Login Persistence Swift

I'm using Firebase to handle my user register and login for my app. But if I log in, and then close my app entirely - the user is forced to re-log in. I'd like to keep the user logged in unless they click "Log out"
My login code is this:
Auth.auth().signIn(withEmail: email, password: password, completion: {(user, error) in
if let firebaseError = error {
print(firebaseError.localizedDescription)
return
}
self.presentTabBar()
})
}
}
How do I keep this user logged in unless specifically told to logout?
Here's a handy full example for 2020:
Anywhere in your iOS+Firebase app, you can simply say:
guard let uid = Auth.auth().currentUser?.uid else {
return print("no current user!")
}
Thus, on the launch screen of your app, simply:
import UIKit
import Firebase
import FirebaseUI
class ViewController: UIViewController, FUIAuthDelegate {
override func viewDidAppear(_ animated: Bool) {
super.viewDidAppear(animated)
guard let uid = Auth.auth().currentUser?.uid else {
return print("no current user, hence AuthUI flow...")
basicAuthUIFlow()
}
print("User .. \(Auth.auth().currentUser?.displayName)")
continueWhenUserPresent()
}
It's that easy. So then as usual ...
private func basicAuthUIFlow() {
let authUI = FUIAuth.defaultAuthUI()
authUI?.delegate = self
let pp: [FUIAuthProvider] = [ FUIGoogleAuth() ]
authUI?.providers = pp
if let authVC = authUI?.authViewController() {
present(authVC, animated: true)
}
}
func authUI(_ authUI: FUIAuth,
didSignInWith authDataResult: AuthDataResult?,url: URL?, error: Error?) {
let u = authDataResult?.user
print("Successful login via authUI \(String(describing: u?.displayName))")
continueWhenUserPresent()
}
private func continueWhenUserPresent() {
.. pushViewController .. your first screen
}
Check if the user is logged in or not:
if Auth.auth().currentUser != nil {
// User is signed in.
// ...
} else {
// No user is signed in.
// ...
}
if the user is logged in, then go the Home ViewController. This way when he opens the app again he will go to the Home ViewController unless he sign outsFIRAuth.auth().signOut()
For more info check this: https://firebase.google.com/docs/auth/ios/manage-users
For keep user login you need to check currentUser Auth session, If it's not nil then you can redirect user to Home screen.
Call "setRootViewController" method from didFinishLaunchingWithOptions, just after FirebaseApp.configure() code
Swift 4
func setRootViewController() {
if Auth.auth().currentUser != nil {
// Set Your home view controller Here as root View Controller
self.presentTabBar()
} else {
// Set you login view controller here as root view controller
}
}

Show View Controller based on the users Firebase login state

In my app I want do display different ViewControllers depending on if the user is already logged in or not. Like if the user is logged in present VC_A if not, present VC_B. I tried the following code in my vc_login:
if let user = FIRAuth.auth()?.currentUser {
let vc = self.storyboard?.instantiateViewController(withIdentifier: "vc_home") as! ViewController_Home
self.present(vc, animated: true, completion: nil)
} else {
// Do Nothing
}
You can do it like that (hints are in the code comments):
if FIRAuth.auth()?.currentUser?.uid == nil {
// user is not logged in
// present VC_B
} else {
// user is logged in
// present VC_A
}
Or you can use the ternary conditional operator like this:
FIRAuth.auth()?.currentUser?.uid == nil ? presentViewControllerB() : presentViewControllerA()
func presentViewControllerA() {
// call if logged in
}
func presentViewControllerB() {
// call if not logged in
}

Firebase user can not be logged out - Swift

I run the app in Xcode simulator and log in with user and password then I log out, the logOutOutlet and bookingsOutlet are hidden and logInOutlet button shows. So far it behaves as expected.
2
Next, stop the app from Xcode and run it again, but now it behaves as if I was already logged in: shows logOutOutlet,bookingsOutlet, hides logInOutlet. It behaves in the same when the app is suspended, terminated or deleted. ( i.e, Stop in Xcode or cmd + H * 2 and swipe up.)
Now, assuming that I have an active logIn session in the next ViewController I try to retrieve data from FireBase Realtime DataBase, but I get this error. Error Domain=com.firebase Code=1 "Permission Denied" UserInfo={NSLocalizedDescription=Permission Denied}. Why can I not log out completely?
#IBAction func logOut(sender: AnyObject) {
// if the current user is logged in, try to log out and if logout is successful:
// hide: logOut button & bookings button
// show: logIn button
if FIRAuth.auth() != nil {
do {
try FIRAuth.auth()?.signOut()
print("the user is logged out")
} catch let error as NSError {
print(error.localizedDescription)
print("the current user id is \(FIRAuth.auth()?.currentUser?.uid)")
}
self.logInOutlet.hidden = false
self.logOutOutlet.hidden = true
self.bookingsOutlet.hidden = true
} // end of if.. FIRAuth.auth()
}
override func viewDidLoad() {
super.viewDidLoad()
// if the user is logged out
// hide: logOut button & bookings button
// show: logIn button
// if FIRAuth.auth()?.currentUser?.uid == nil {
if FIRAuth.auth() == nil {
self.logInOutlet.hidden = false
self.logOutOutlet.hidden = true
self.bookingsOutlet.hidden = true
// it still prints the user id, why?
if let userNOTLogged = FIRAuth.auth()?.currentUser?.uid {
print("User should NOT be logged \(userNOTLogged)")
}
// if the user is logged in
// hide: logIn Button
// show: logOut button & bookings button
} else if
FIRAuth.auth() != nil {
self.logInOutlet.hidden = true
self.logOutOutlet.hidden = false
self.bookingsOutlet.hidden = false
}
}
// Log in code
FIRAuth.auth()?.signInWithEmail(email.text!, password: password.text!, completion: { (authData, error) in
let customError = error?.localizedDescription
if error != nil {
print(customError)
// display an alert with the error
self.displayAlert()
} else {
print("The user has been logged in")
//if signIn was successful, instantiate the view controller with identifier SWrevelViewidentifier
let toMenuOptions = self.storyboard?.instantiateViewControllerWithIdentifier("SWrevelViewidentifier")
self.presentViewController(toMenuOptions!, animated: true, completion: nil)
}
})
}
I had this exact same problem. Since this happens when you relaunch, try putting this code in your app.delegate.
FIRAuth.auth()?.addAuthStateDidChangeListener { auth, user in
if let user = user {
// User is signed in.
} else {
// No user is signed in.
}
}

how to segue to 2nd page from successful login - "warning attempt to present on while a presentation is in progress" error

How do I segue to my 2nd page after successfully verifying login?
I have pulled a segue from the login page view controller (not the login button) to the next page and named the segue 'nextPage'. (If I segue from the login button then the button click allows all logins to segue through without testing them). When I segue from the login page it correctly checks details but does not segue to the next page on successful login, and instead I get the console error "Warning: Attempt to present on while a presentation is in progress!"
the code is
#IBAction func loginButtonTapped(sender: AnyObject) {
let userEmail = userEmailTextField.text;
let userPassword = userPasswordTextField.text;
let userEmailStored = NSUserDefaults.standardUserDefaults().stringForKey("userEmail");
let userPasswordStored = NSUserDefaults.standardUserDefaults().stringForKey("userPassword");
if userEmailStored == userEmail && userPasswordStored == userPassword {
// Login successful
// Display an alert message
displayMyAlertMessage("Login successful. Thank you");
NSUserDefaults.standardUserDefaults().setBool(true,forKey:"isUserLoggedIn");
NSUserDefaults.standardUserDefaults().synchronize();
print("login success!")
self.dismissViewControllerAnimated(true, completion:nil);
self.performSegueWithIdentifier("nextPage", sender: self);
} else if userEmailStored != userEmail {
// Login unsuccessful (email incorrect)
NSUserDefaults.standardUserDefaults().setBool(false,forKey:"isUserLoggedIn");
print("login unsuccessful. Incorrect email.")
// Display an alert message
displayMyAlertMessage("Incorrect login details.");
return;
} else if userPasswordStored != userPassword {
// Login unsuccessful (password incorrect)
// Display an alert message
displayMyAlertMessage("Incorrect login details");
//return;
NSUserDefaults.standardUserDefaults().setBool(false,forKey:"isUserLoggedIn");
print("login unsuccessful. Incorrect password.")
}
The login page comes after an initial 'protected' login/logout screen as ViewController.swift with this code
override func viewDidAppear(animated: Bool)
{
let isUserLoggedIn = NSUserDefaults.standardUserDefaults().boolForKey("isUserLoggedIn");
if(!isUserLoggedIn)
{
self.performSegueWithIdentifier("loginView", sender: self);
}
}
#IBAction func logoutButtonTapped(sender: AnyObject) {
NSUserDefaults.standardUserDefaults().setBool(false,forKey:"isUserLoggedIn");
NSUserDefaults.standardUserDefaults().synchronize();
self.performSegueWithIdentifier("loginView", sender: self);
}
}
I do suggest to have a different approach on this.
If you set a storyboardID to LoginViewController you can directly manage to override the Protected page checking directly in AppDelegate.
For example you can try to do this
func application(application: UIApplication, didFinishLaunchingWithOptions launchOptions: [NSObject: AnyObject]?) -> Bool {
[...]
let isUserLoggedIn = NSUserDefaults.standardUserDefaults().boolForKey("isUserLoggedIn")
if isUserLoggedIn {
let storyboard = UIStoryboard(name: "Main", bundle: NSBundle.mainBundle())
let vc = storyboard.instantiateViewControllerWithIdentifier("IDYOUSETBEFORE")
window.rootViewController = vc
return
}
I recently managed to release a pod in order to easily handle this situations, have a look at StoryboardEnum lib
I solved this by removing the alert controller function, i.e. the code
displayMyAlertMessage("Login successful. Thank you");
as this was segueing to the 'login successful' popup view controller, instead of the segue that I needed, and in effect blocking the next page, while also not really necessary, as successful login means moving to the next page. I was able to still keep the alert/ popups for 'incorrect login details' which were the only essential alerts.