20

I am using newest Firebase API (3.2.1) and I am using this code to check if user is signed in:

override func viewDidAppear(animated: Bool) {
    super.viewDidAppear(animated)

    if(self.navigationController != nil){
        self.navigationController!.setNavigationBarHidden(true, animated: true)
    }

    if(FIRAuth.auth() != nil){
        self.performSegueWithIdentifier("loginSuccessSegue", sender: self)
    }
}

In other words if auth object is present I am switching to other controller. On that controller I have sign out button which is doing sign out like this:

do{
    try FIRAuth.auth()?.signOut()
    self.performSegueWithIdentifier("logoutSegue", sender: self)
}catch{
    print("Error while signing out!")
}

I do not get error on this operation but when I am switched to login controller, this auth object is present and I get switched back again to controller with data. I also tried checking the current user object in auth and it is present and valid.

Anyone knows how an I properly do sign out?

Dejan
  • 3,046
  • 3
  • 28
  • 43
  • 1
    I just implemented this in my own app, with a little help from Wiley at Firebase. You can add a listener as I have described in [this](http://stackoverflow.com/questions/39301815/firebase-ios-swift-firauth-auth-signout-not-signing-out-current-user#answer-40412452) answer. – Nick Kohrn Nov 03 '16 at 22:48

4 Answers4

42

try using :

try! FIRAuth.auth()!.signOut()

This is the code I have in an IBAction, and it's working just fine :

try! FIRAuth.auth()!.signOut()     
if let storyboard = self.storyboard {
    let vc = storyboard.instantiateViewControllerWithIdentifier("firstNavigationController") as! UINavigationController
        self.presentViewController(vc, animated: false, completion: nil)
    }

Swift 4.2 Update #

try! Auth.auth().signOut()

if let storyboard = self.storyboard {
            let vc = storyboard.instantiateViewController(withIdentifier: "firstNavigationController") as! UINavigationController
            self.present(vc, animated: false, completion: nil)
        }
Damien
  • 3,322
  • 3
  • 19
  • 29
  • I am not understanding what would I achieve with this, and I tried it but it still does not work. – Dejan Jun 22 '16 at 07:34
  • That worked for me. All I can recommend is to create a new project and set a basic log in / log out just as you made it in your real project. If it still doesn't work, then you have something wrong in the way you're using it, otherwise just look at what's different. – Damien Jun 22 '16 at 16:18
  • 1
    @Damien Bannerot even if you successfully run try! FIRAuth.auth()!.signOut(), the .currentUser.uid will remain stored in keychain. If anybody knows how to fix this, feel free to post the correct answer. – bibscy Aug 25 '16 at 19:39
  • @bogdanbarbulescu : does Firebase use keychain ? – Damien Aug 25 '16 at 21:58
  • @Damien Bannerot The Firebase authentication session is persisted on the user's device in the iOS keychain. There is an explanation on stackoverflow [LINK](http://stackoverflow.com/questions/27893418/firebase-deleting-and-reinstalling-app-does-not-un-authenticate-a-user) . Can you post a sample code on how to delete the session that is stored in keychain? When the user logges in, do nothing because the session is automatically saved by Firebase, when the user logges out, delete the Firebase session. After this in viewDidLoad, if I check for .currentUser.uid ,the result should be nil. – bibscy Aug 26 '16 at 10:53
  • @bogdanbarbulescu : the thing is I didn't touch anything else than what's on the doc. Look at my edit in answer. – Damien Aug 26 '16 at 12:49
  • `try!` force unwraps your code and guarantees that your function will never encounter an error. In the case that `signOut()` function does throw an error your app will simply crash. So, OPs code is correct, but there is something else that is causing the issue here. – Anjan Biswas Nov 27 '17 at 07:45
12

2020 ...

do { try Auth.auth().signOut() }
catch { print("already logged out") }

Typically, on your "base" screen, something like ...

func logoutUser() {
    // call from any screen
    
    do { try Auth.auth().signOut() }
    catch { print("already logged out") }
    
    navigationController?.popToRootViewController(animated: true)
}
Community
  • 1
  • 1
Fattie
  • 27,874
  • 70
  • 431
  • 719
6

I'd just like to add that I had the same problem and have been trying various combinations of the code that others have suggested.

The problem for me turned out to be that when I set up my Logout button in the storyboard, I also created a connection by control dragging from the button to my login view controller, thinking that that was what I wanted it to do.

It turned out that my signout code never ran because of the Triggered Segue back to login controller, so it went back to the login screen and immediately to my second view controller because the user was never logged out.

So in the end this worked for me:

do {
    try Auth.auth().signOut()
    self.dismiss(animated: true, completion: nil)
    } catch let err {
        print(err)
}

But only after I deleted the segue I had unwittingly created.

Adam Webb
  • 61
  • 1
  • 2
1

None of the previous answers worked for me so I tried using the provider-specific signOut method and it actually removed the authentication state from the keychain.

GIDSignIn.sharedInstance.signOut()
Clark McCauley
  • 1,342
  • 5
  • 16