Firebase Login Persistence Swift - 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
}
}

Related

sign out for Facebook and Google

I am trying to implement a sign out button that depending on the current user type (Facebook vs Google) it will sign out based on which type of current user is logged in. I am able to login with different accounts but want the sign out function to be conditional based on what type of account is logged in...thanks in advance!
// sign out functions
func handleSignOut() {
// facebook sign out
UserDefaults.standard.setIsLoggedIn(value: false)
FBSDKLoginManager().logOut()
print("did log out of facebook...")
// google signout
let firebaseAuth = FIRAuth.auth()
do {
try firebaseAuth?.signOut()
} catch let signOutError as NSError {
print ("Error signing out: %#", signOutError)
}
let loginController = LoginController()
present(loginController, animated: true, completion: nil)
}
func loginButtonDidLogOut(_ loginButton: FBSDKLoginButton!) {
do {
try FIRAuth.auth()!.signOut()
} catch let logoutError {
print(logoutError)
}
}
Try storing in the UserDefaults which account your user is signed in as (e.g. store a "account" key with a string value "google" or "facebook").
Then, in your sign-out method, handleSignOut() {...}, test for that value, i.e.
let at = (UserDefaults.getAccountType())
if at == "google" {
handleGoogle()
} else if at == "facebook" {
handleFacebook()
}
*Implement your own accessor for UserDefaults.getAccountType

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
}

Logout on Facebook's Firebase

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
}

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.

Swift 2.0 working Facebook custom login button

I beg all of thee. I searched everywhere but i can't find working swift 2.0 code for Facebook custom login button with returning Access Token. My code simply don't work. (token is not returning Facebook token)
Considering that you have done all the setup as described by the Facebook developer page, you need to do the following in your login view controller:
// Import the following on top below "import UIKit" in your login view controller
import FBSDKCoreKit
import FBSDKLoginKit
// This is your action code for your custom login button for login using facebook in Swift
#IBAction func fbLoginBtn(sender: AnyObject) {
let permisions = ["public_profile", "email"]
PFFacebookUtils.logInInBackgroundWithReadPermissions(permisions) {
(user: PFUser?, error: NSError?) -> Void in
if let error = error {
print(error)
} else {
if let user = user {
print(user)
// "yourSegue" below will be the segue identifier for your new view.
self.performSegueWithIdentifier("yourSegue", sender: self)
}
}
}
}
In case you have not setup your app at Facebook developer, please following the simple steps as mentioned in Facebook Developer Page.
1 - Add a normal button in your view then add the FB login class "FBSDKLoginButton"
2 - Declare your button in your ViewController
#IBOutlet weak var FBLoginButton: FBSDKLoginButton!
3 - Add in your ViewDidload methode
if (FBSDKAccessToken.currentAccessToken() != nil)
{
// User is already logged in, do work such as go to next view controller.
}
else
{
self.FBLoginButton.delegate = self
FBLoginButton.readPermissions = ["public_profile", "email", "user_friends"]
}
4-Add Delegate Login and logout button funcutions
func loginButton(loginButton: FBSDKLoginButton!, didCompleteWithResult result: FBSDKLoginManagerLoginResult!, error: NSError!) {
loginButton.readPermissions = ["public_profile", "email", "user_friends"]
let fbAccessToken = FBSDKAccessToken.currentAccessToken().tokenString
FBSDKGraphRequest(graphPath: "me?fields=id,name,email,gender,first_name,last_name,middle_name,birthday&access_token=\(fbAccessToken)", parameters: nil).startWithCompletionHandler({ (connection, result, error) in
if ((error) != nil) {
// Process error
print("Error: \(error)")
} else {
print("fetched user: \(result)")
}
})
}
func loginButtonDidLogOut(loginButton: FBSDKLoginButton!) {
print("User Logged Out")
}