Twitter / Fabric login button not behaving as expected - ios

I have a very simple iOS project where I'm using Twitter/Fabric login button for user login to my app.
I've managed to get the Fabric login button working. When the user clicks on the Twitter login button they are automatically authenticated (that's if they are logged into the Twitter app) otherwise the user is presented with a Twitter login screen.
I'm not sure why the user is automatically authenticated when they are logged into the Twitter app on their phone.
Is there a way to use the Twitter/Fabic API to open the Twitter app and ask for permission to grant access to my app similar to Facebook login even if the user is logged into the Twitter App.
This is what my AppDelegate looks like:
Twitter.sharedInstance().start(withConsumerKey: "someKey", consumerSecret: "someSecret")
Fabric.with([Twitter.self])
This is what my ViewController looks like:
#IBOutlet private weak var twitterLoginButton: TWTRLogInButton!
// and
twitterLoginButton.logInCompletion = {(session, error) in
if error != nil {
print("ERROR: \(error)")
} else {
if let unwrappedSession = session {
print(unwrappedSession.userName)
}
}
}
Twitter.sharedInstance().logIn { (session, error) in
if let unwrappedSession = session {
print("Signed in as: \(unwrappedSession.userName)")
} else {
print("ERROR: \(error)")
}
}

Fabric documentation says that the first default for login is to go through the Twitter app (that may be why your user is automatically authenticated if they're already logged in the app), otherwise it will go through the webAuth login flow.
"To force the log in flow to use the web OAuth flow pass the TWTRLoginMethodWebBased method to the relevant log in methods."
// If using the TWTRLoginButton
let logInButton = TWTRLogInButton() { session, error in
}
logInButton.loginMethods = [.webBased]
So if you want to force the user to go through the web flow, try adding to your code: twitterLoginButton.loginMethods = [.webBased]

Related

Swift: Linking Facebook users with existing PFUsers Not Working on Parse Server

I'm trying to integrate the Facebook login/signup into my app to work alongside the standard login/signup with email. I am using Swift and have migrated to Parse Server.
I've followed the Parse iOS guide on Facebook Users. However, with Parse Server, the Facebook integration isn't working normally according to all the tutorials and documentation out there.
How can I link existing PFUsers with their Facebook accounts when they log in with Facebook in the app?
I am using the Swift code from this section of the guide (https://parse.com/docs/ios/guide#users-linking) to associate an existing PFUser to a Facebook account (see code below), however, this code is not executing for some unknown reason and therefore is not linking a users existing account they created through the email sign up with their Facebook account which has the same email. Why is this code not executing?
UPDATE: The isLinkedWithUser method requires that the user be logged in. However, when a user is signed out/just downloaded the app, the PFUser.currentUser() is nil because the user is not logged in. Therefore, the linkUserInBackground method won't know which PFUser to link the Facebook account with. I believe these methods are now useless because they are to link after the fact (after they log in). But I don't want to create two users.
Is there a Cloud Code example or other Swift logic to accomplish this?
I am not sure what the problem is. Appreciate any help!
Source: https://parse.com/docs/ios/guide#users-facebook-users
func fbLoginButtonTapped() {
print("fbLoginButtonTapped")
let permissions = ["public_profile", "email"]
PFFacebookUtils.logInInBackgroundWithReadPermissions(permissions, block: {
(user: PFUser?, error: NSError?) -> Void in
if let user = user {
if user.isNew {
print("User signed up and logged in through Facebook!")
} else {
print("User logged in through Facebook!")
// This API doesn't seem to be working with Parse Server
if !PFFacebookUtils.isLinkedWithUser(user) {
PFFacebookUtils.linkUserInBackground(user, withReadPermissions: nil, block: {
(succeeded: Bool?, error: NSError?) -> Void in
if error == nil {
print("Woohoo, the user is linked with Facebook!")
} else {
print("User is not linked with Facebook.")
}
})
}
dispatch_async(dispatch_get_main_queue(), { () -> Void in
let viewController = UIStoryboard(name: "Main", bundle: nil).instantiateViewControllerWithIdentifier("HomeNavigationController") as! UINavigationController
self.presentViewController(viewController, animated: true, completion: nil)
})
}
} else {
print("User cancelled the Facebook login.")
}
}
Did you configure the FBSDK correctly in your Swift app? You should need to add a few callbacks in your app delegate that handle FBSDK (https://developers.facebook.com/docs/ios/getting-started/).
Also, was that app running on parse.com or are you using it for the 1st time on parse-server?

Removing Firebase authState upon viewDidDisappear

I'm using Firebase's new framework and I'm attempting to monitor the login state of the user on both the Login and Signup VC's separately. The problem is if the login state changes on the SignUp view the Auth State on the Login view gets called as well. My question is, how do I remove the auth state? I found the syntax on the Firebase website but am a little confused on what to pass in considering my code for the auth state:
FIRAuth.auth()?.addAuthStateDidChangeListener { auth, user in
if let theUser = user {
// User is signed in.
print("LOGGED IN!!!! :::: \(theUser)")
self.dismissViewControllerAnimated(true, completion: nil)
} else {
// No user is signed in.
print("Need to login first.")
}
}
Code to use to remove the auth, but unsure what to pass in.
FIRAuth.auth()?.removeAuthStateDidChangeListener(FIRAuthStateDidChangeListenerHandle)
Says I pass in a FIRAuthStateDidChangeListenerHandle, but how do I obtain this, or do I rewrite my authState code differently?
Just store the auth in a variable
self.authListener = FIRAuth.auth()?.addAuthStateDidChangeListener { auth, user in
if let theUser = user {
// User is signed in.
print("LOGGED IN!!!! :::: \(theUser)")
self.dismissViewControllerAnimated(true, completion: nil)
} else {
// No user is signed in.
print("Need to login first.")
}
}
and remove it later
FIRAuth.auth()?.removeAuthStateDidChangeListener(self.authListener)

Is it normal to ask "you have already authorize " through Facebook SDK

This is just a question, if I log in once with Facebook login using the latest SDK and then I try to log in again, its asking me "you have already authorize app name". Is it normal or Do I have to change something to avoid it.
In my scenario, I made SSO on in Facebook App Setting this does not resolve the issue!!
Whenever my login window shows, I logout the Facebook and clear the access token, first I thought because of this, this is being asked however, I omitted the code and still it is asking!!
I can post code if necessary!!!
override func viewDidLoad() {
super.viewDidLoad()
fbloginButton.delegate = self
fbloginButton.readPermissions = ["public_profile", "email", "user_friends"]
if (FBSDKAccessToken.currentAccessToken() != nil)
{
var loginM:FBSDKLoginManager = FBSDKLoginManager()
loginM.logOut()
FBSDKAccessToken.setCurrentAccessToken(nil)
}
}
#IBAction func loginFb(sender:AnyObject)
{
fbLoginManager.logInWithReadPermissions(["email"], fromViewController: self.presentingViewController, handler: { (result, error) -> Void in
if (error == nil){
var fbloginresult : FBSDKLoginManagerLoginResult = result
}
})
}
func loginButton(loginButton: FBSDKLoginButton!, didCompleteWithResult result: FBSDKLoginManagerLoginResult!, error: NSError!) {
NSLog("didCompleteWithResult")
if ((error) != nil)
{
}
else if result.isCancelled {
}
else {
// If you ask for multiple permissions at once, you
// should check if specific permissions missing
if result.grantedPermissions.contains("email")
{
///Here I call a function to get data
}
}
It's been a while since I've worked with the Facebook SDK, but I think when you logout, you just invalidate your current accessToken and end your session, but it does not deauthorize your app.
So, when you login, you just generate a new accessToken for the FB app that you already authorized. You need to login again (to verify your identity), but you don't need to authorize again, hence it's giving you that message.
There's a Graph API call to revoke permissions, if that is what you are looking for.
And if your question is whether this is "normal". Yes, I'd say that's normal. It's a visual indication that you are at that point connecting again with a previously authorized FB app. Avoiding it might work by not sending any permissions, but you generally don't know if an already authorized user is logging in again, or a completely new user. If the latter logs in without permissions, well, your app wouldn't work as supposed too.

How to change a parse's Facebook account custom fields

I am trying to enable login with a Facebook account for my new social app but I need to know how to change custom Facebook accounts fields in parse so I can know if a Facebook user already set up his account or not. I managed to do it with regular accounts but now with Facebook accounts
Here is my method:
PFFacebookUtils.logInInBackgroundWithReadPermissions(permissions) {
(user: PFUser?, error: NSError?) -> Void in
if let user = user {
if user.isNew {
println("User signed up and logged in through Facebook!")
self.performSegueWithIdentifier("procceedToSetup", sender: self)
// I need to change here a parse field named "doneSetUp" with a type of a bool to false.
} else {
self.performSegueWithIdentifier("procceedToApp", sender: self)
}
} else {
println("Uh oh. The user cancelled the Facebook login.")
}
}
When a Facebook user completes the setup he/she will press the complete button and it will change the variable "doneSetUp" to true, I do it so Facebook accounts won't exit the app in the middle of the setup and when they log in back they will access the app without setup.
By the way, I would like to know how can I access Facebook account fields I chose with the permissions array, such as country, profile picture, name, etc...
Thanks for all the helpers!
Jeez, I found the reason.
forgot to put
PFUser.currentUser()?.save()
at the end.

How do I store & access a Twitter Fabric login session (iOS/Swift)?

I'm able to log in to Twitter through my app using this Twitter Fabric code:
let logInButton = TWTRLogInButton(logInCompletion: {
(session: TWTRSession!, error: NSError!) in
// play with Twitter session
if (session != nil) {
println("signed in as \(session.userName)");
self.TWUsernameLabel.text = "Logged in as #" + session.userName
} else {
println("error: \(error.localizedDescription)");
}
})
When I click the login button, it prompts me to approve the login and then logs me in, or it knows I already approved the login and it logs me in. This works like a charm and took all of ten minutes to set up. Amazing.
I already have an email-based login to access the app. I'd like to store a user's logged in Twitter account in that same database, so when a user logs in with their email, I already know their Twitter (if they have logged in before) and they don't need to log in again. The reason I do the email login is because Twitter is an important feature in my app, but not a total requirement.
The issue is that I have no idea how to access session outside of when the button is clicked and logInCompletion fires, and I don't know what variables to store upon initial login/check upon using the app.
I've read through the Twitter Fabric documentation numerous times, but it isn't written in swift, so it's pretty confusing. Any ideas? Thanks
If there is currently an active session you should be able to access it just like the docs say to
Twitter.sharedInstance().session()
If the user isn't logged in that method will return nil. If you want to know if someone is already authenticated just check to see if that method returns a value or not.
Twitter kit automatically present a login screen if user has not logged in (no session exist..).
But, before calling any future API, just check whether session is valid or not. In some APIs, you may required to pass this session too.
if ([[Twitter sharedInstance] session]) {
TWTRShareEmailViewController *shareEmailViewController =
[[TWTRShareEmailViewController alloc]
initWithCompletion:^(NSString *email, NSError *error) {
NSLog(#"Email %# | Error: %#", email, error);
}];
[self presentViewController:shareEmailViewController
animated:YES
completion:nil];
} else {
// Handle user not signed in (e.g. attempt to log in or show an alert)
}
}
You even don't need to worry about storing and managing access token and access token secret.
To access the authToken, userName or the userID for the logged in user session in Swift 4 is:
Twitter.sharedInstance().logIn(completion: { (session, error) in
if (session != nil) {
print(session!.authToken)
print(session!.userName)
print(session!.userID)
} else {
print(error?.localizedDescription)
}
})

Resources