Firebase - iOS Swift: FIRAuth.auth().signOut() not signing out current user
Solution 1
You can add a listener in your viewDidAppear
method of your view controller like so:
FIRAuth.auth()?.addStateDidChangeListener { auth, user in
if let user = user {
print("User is signed in.")
} else {
print("User is signed out.")
}
}
This allows you to execute code when the user's authentication state has changed. It allows you to listen for the event since the signOut
method from Firebase does not have a completion handler.
Solution 2
GIDSignIn.sharedInstance().signOut()
Solution 3
I actually had this issue as well. I was also logging out the user (as you are) with the method's provided by Firebase but when I printed to the console it said that I still had a optional user.
I had to change the logic of setting the current user so that it is always configured by the authentication handler provided by Firebase:
var currentUser: User? = Auth.auth().currentUser
var handle: AuthStateDidChangeListenerHandle!
init() {
handle = Auth.auth().addStateDidChangeListener { (auth, user) in
self.currentUser = user
if user == nil {
UserDefaults.standard.setValue(false, forKey: UserDefaults.loggedIn)
} else {
UserDefaults.standard.setValue(true, forKey: UserDefaults.loggedIn)
}
}
}
As long as you are referencing the current user from this handle, it will update the current user no matter the authentication state.
Solution 4
Some answers are using a force unwrap when the firebase signing out method can throw an error. DO NOT DO THIS!
Instead the call should be done in a do - catch - block as shown below
do {
try Auth.auth().signOut()
} catch let error {
// handle error here
print("Error trying to sign out of Firebase: \(error.localizedDescription)")
}
You can then listen to the state change using Auth.auth().addStateDidChangeListener and handle accordingly.
Solution 5
Use exclamation points not question marks.
try! FIRAuth.auth()!.signOut()
alexisSchreier
Updated on June 15, 2022Comments
-
alexisSchreier almost 2 years
I'm building an app using Firebase with an initial
SignInViewController
that loads a sign in page for users to authenticate with email which triggers the following methods:@IBAction func didTapSignIn(sender: AnyObject) { let email = emailField.text let password = passwordField.text FIRAuth.auth()?.signInWithEmail(email!, password: password!) { (user, error) in if let error = error { print(error.localizedDescription) return } self.signedIn(user!) } } func signedIn(user: FIRUser?) { AppState.sharedInstance.displayName = user?.displayName ?? user?.email AppState.sharedInstance.signedIn = true NSNotificationCenter.defaultCenter().postNotificationName(Constants.NotificationKeys.SignedIn, object: nil, userInfo: nil) performSegueWithIdentifier(Constants.Segues.SignInToHome, sender: nil) }
The
SignInViewController
also checks if there is a cached current user when the app launches and, if so, signs that user in:override func viewDidAppear(animated: Bool) { super.viewDidAppear(true) //Synchronously gets the cached current user, or null if there is none. if let user = FirebaseConfigManager.sharedInstance.currentUser { self.signedIn(user) } }
Once the user is signed in, the app segues to a
HomeScreenViewController
which displays a "Sign Out" button at the top left of the navigation bar. When a user taps the "Sign Out" button, that user is supposed to get signed out and the app should segue back to theSignInViewController
with the following method:@IBAction func didTapSignOut(sender: UIBarButtonItem) { print("sign out button tapped") let firebaseAuth = FIRAuth.auth() do { try firebaseAuth?.signOut() AppState.sharedInstance.signedIn = false dismissViewControllerAnimated(true, completion: nil) } catch let signOutError as NSError { print ("Error signing out: \(signOutError)") } catch { print("Unknown error.") } }
When I tap the "Sign out" button, the
didTapSignOut
method gets called and gets executed. However, after thetry firebaseAuth?.signOut()
line of code gets executed, the current user should benil
. But when I print out the current user in the Xcode console, the current user is still logged in:po FIRAuth.auth()?.currentUser ▿ Optional<FIRUser> - Some : <FIRUser: 0x7fde43540f50>
Since the current user doesn't get signed out after
firebaseAuth?.signOut()
gets called, once the app segues back to theSignInViewController
the app still thinks there is a cached current user so that user gets signed in again.Could this be a Keychain issue?
Does it have to do with
NSNotificationCenter.defaultCenter().postNotificationName
being called?My code comes directly from the Google Firebase Swift Codelab so I'm not sure why it's not working: https://codelabs.developers.google.com/codelabs/firebase-ios-swift/#4
-
alexisSchreier over 7 yearsThanks for your answer @rMickeyD. I'm still getting the same result though. I edited my code to
try! FIRAuth.auth()!.signOut()
like you suggested but the current user still exists in cache when viewWillAppear(animated:Bool) gets called and checks for the user in theSignInViewController
. -
AnBisw over 6 yearsnever Force unwrap (
!
) atry
, your app will crash if you force unwrap and thesignOut
does encounter an error. For example,signOut
will most definitely throw an error if the user has no internet connectivity (or in Airplane mode), in this case your app will most definitely crash.