Confusion about session objects in Facebook Connect for iPhone - iphone

I've done a lot of reading of the Facebook docs, but I'm pretty confused about the role of the session object. For instance, with the method:
session = [FBSession sessionForApplication:myApiKey secret:myAppSecret delegate:self];
What am I supposed to do with the session object that's returned to me, when presumably I need to wait for the delegate callback in order to do anything?
Secondly...upon a later execution of my app, when the user has authorized me accessing their account during a previous execution, how do I get a reference to a session object so I can connect to their Facebook account and post status, etc.? The docs mention [session resume], but don't say where that session reference is supposed to come from. (And calling [[FBSession session] resume] compiles, but doesn't work.)
Thanks.

What am I supposed to do with the session object that's returned to me, when presumably I need to wait for the delegate callback in order to do anything?
You have to create and show a FBLoginDialog to the user. The delegate method will not be called until the user has logged in. It has nothing to do with creating the session instance in the first place.
how do I get a reference to a session object so I can connect to their Facebook account
The Facebook Connect library will store the session info in your app's user defaults. You don't have to do anything to store it. As I understand it, on every launch of your app you should create the session object with +sessionForApplication:secret:delegate: and then call [session resume]. If the FBConnect library finds a valid session stored in the user defaults, it will return YES and you can proceed as the user is now logged in. If resume returns NO, you will have to show the login dialog.
From Facebook's docs:
The session information will be stored on the iPhone disk in your application's preferences, so you won't have to ask the user to log in every time they use your application. After you've created your session object, call [session resume] to resume a previous session. If the session has expired or you have yet to create a session, it will return NO and you will have to ask your user to log in. Sessions expire after two hours of inactivity.

this is really following on from Ole's answer and comments as it is all in there. This is what I did.
Firstly create the session object:
facebookSession = [[FBSession sessionForApplication:SESSION secret:SECRET delegate:self]retain];
[facebookSession resume];
The second line pulls the session data from the settings file to keep you logged on if the user specifies that they'd like to be kept logged on.
You have to implement the method:
- (void)session:(FBSession*)session didLogin:(FBUID)uid
although I don't use it for anything.
To check if the user is already logged on, I call:
[[FBSession session] isConnected]
and then either display the login dialog or straight to the publish dialog if they are already logged on.

Related

facebook-ios-sdk logout question

I have seen a lot of questions here regarding the Facebook Graph API but I still haven't find a solution for simple 'login'/'logout' operations using it. Looks like the Single Sign-On style is causing more confusion than benefits.
I'd like to know if it is possible have the following situation:
Enter in the app (no accessToken/expirationDate created).
Perform a login using SSO by calling authorize:delegate: method (application goes background and the login is made in the 'global' scope (Facebook App/Mobile Safari), asking for the user credentials.
Enter back in the app (now logged in, both accessToken and expirationDate are saved to NSUserDefaults).
Perform a logout by calling the logout: method (now logged out, both accessToken and expirationDate are removed from NSUserDefaults)
Attempt to perform a login again, with exactly the same steps done in 2.
I realize that when I call logout:, I do really log out from Facebook (accessToken is invalidated) from my App scope, not from the global scope (Facebook App/Mobile Safari). In 5.) when I try to log in again, the application goes to background and the login attempt is made again in Facebook App/Mobile Safari as usual, however I'm getting a screen saying that I'm already logged in:
You have already authorized .... Press "Okay" to continue.
Logged in as ... (Not You?).
It's a strange behavior for the user that has just logged out in my App.
My question is:
"Can I really log out from facebook (I mean 'global' scope) from inside my App? This would affect other apps using the facebook credentials too. However, if I can't to do this, how can I avoid the 'strange behavior' describe above?
Thanks
Eduardo,
I feel your pain! I spent the better part of a day working on this issue. I have discovered that when you use SSO and the call:
Called from your code:
[facebook logout:self];
Facebook API method:
- (void)logout:(id<FBSessionDelegate>)delegate {
self.sessionDelegate = delegate;
[_accessToken release];
_accessToken = nil;
[_expirationDate release];
_expirationDate = nil;
NSHTTPCookieStorage* cookies = [NSHTTPCookieStorage sharedHTTPCookieStorage];
NSArray* facebookCookies = [cookies cookiesForURL:[NSURL URLWithString:#"http://login.facebook.com"]];
for (NSHTTPCookie* cookie in facebookCookies) {
[cookies deleteCookie:cookie];
}
if ([self.sessionDelegate respondsToSelector:#selector(fbDidLogout)]) {
[_sessionDelegate fbDidLogout];
}
}
The facebook API does invalidate the access token and expirationdate variables and attempts to delete the mobile Safari cookies, but for some reason, probably Apple's fault the cookies are not really deleted. So when you attempt to login in the next time your mobile Safari will see the cookie and it says:
"You have already authorized .... Press "Okay" to continue. Logged in as ... (Not You?)."
Until either Facebook finds a fix or Apple fixes their broken API we must bypass SSO through Safari. Below are the changes I made to Facebook.m in order to force the old login dialog. If you used these changes they may not work forever but it is my guess that they will work for a very long time. Also to be sure this worked with the most recent facebook API I updated to the latest as of this post (Nov 2011 build).
Called from your code:
[facebook authorize:permissions];
Facebook API method:
- (void)authorize:(NSArray *)permissions {
self.permissions = permissions;
// [self authorizeWithFBAppAuth:YES safariAuth:YES];
[self authorizeWithFBAppAuth:NO safariAuth:NO];
}
If this helps you please up rate this thread and my post to help others find it.
gadildafissh
I'm afraid the answer is no, you can't do this.
Your application is in a sandbox, and can't write outside, where global cookies are (for mobile safari) and Facebook app settings (in Facebook app preferences/cookies I think)
You can only warn your user to logout outside of your app...
...Or you can just not use facebook api SSO, but in app login webform, like I do for other reasons.
If you choose that option this pull request might save you some time ;)
Hii ,
its not possible , the reason is for Single Sign On (SSO) is not to make user login everytime, he logouts , instead if the user logs in anyone of FB enabled apps - it will use that to login again - This is because the device is mostly used by single person in this case only one user can login in Facebook.
you can't control any app outside of your app - for Example - if u login with Gmail & when you open google.com you can see your username there is currently logged In which has SSO,
In new SDK of Facebook, you can set login button loginBehaviour property
Below code in swift ...
let fbButton = FBSDKLoginButton()
fbButton.loginBehavior = .Web
Answer already done, but I just want to clarify it. May be it saved somebody's time.
Go to Facebook.m and change line
[self authorizeWithFBAppAuth:YES safariAuth:YES];
to
[self authorizeWithFBAppAuth:YES safariAuth:NO];
It will cause login window appear inside the app. Logout will work perfect. In other words, it will work as it used to in older versions of OS.
in addition to kishnan94 answer. the objective c version is ;
if you want a modal to open up and ask for facebook credentials seperately from Safari or Facebook app, just use the latest facebook sdk and set the login behaviour
FBSDKLoginManager *login = [[FBSDKLoginManager alloc] init];
[login setLoginBehavior:FBSDKLoginBehaviorWeb];
this will make the logout process more convenient and less confusing for users without using safari or facebook app accounts.
It seems that this is a bug of Facebook SDK. In a case of the Facebook app is installed on device, access_token is renewed. In other hand, access_token and expirationDate could not be changed. :((

FaceBook iOS - check if my facebook app is allready authorized

My question is how to check if my FaceBook app is already authorized for posts by the user, can't find any info on that.
I'm using:
Facebook* facebook = [[Facebook alloc] initWithAppId:#"1234567"];
[facebook authorize:[NSArray arrayWithObjects:#"read_stream", #"offline_access",nil] delegate:self];
A dialog pops up asking me to authorize the app, when done i'm all fine, can do a:
[facebook dialog:#"feed" andDelegate:self];
to post notes on that app.
But, if the user blocks or removes the app i want to do the authorize again before showing the dialog for posting, can't find a way of getting that kind of info before calling authorize.
Any help is appreciated.
Thanks.
I had to deal with this issue too.
When calling the dialog method, you send a delegate that should conform to FBDialogDelegate, which has a method that is called when the dialog fails to load due an error. But in the case the app has been unauthorized, the dialog shows a login screen to the user, but after setting the user and password, a second form appears, letting the user know that an error has occurred. The delegate is also called, but the error received just states that he method has failed with no exact reason why, or even an error number. This method should be called with the correct error, before anything, so the application could act accordingly.
So I found a work around, maybe this is not the best way, but it certainly works. Any call that you do to the Facebook graph api via a request, will fail if the app has been unauthorized by the user. So what I did was to check that before calling the feed dialog method.
Add the following line where you need to test if the app is still authorized:
if ([facebook isSessionValid])
//isSessionValid only checks if the access token is set, and the expiration date is still valid. Lets make a call and see if we really are authorized to post to this user from this app.
[facebook requestWithGraphPath:#"me" andDelegate:self];
else
//authorize Facebook connect
This will just call the method that returns the basic information from the user. If everything is fine, the following method will be called from the delegate:
- (void)request:(FBRequest *)request didLoad:(id)result
{
//Everything is ok. You can call the dialog method. It should work.
}
If the app has been unauthorized by the user, the following method from the delegate will be called:
- (void)request:(FBRequest *)request didFailWithError:(NSError *)error;
{
NSString *type = [[[error userInfo] objectForKey:#"error"] objectForKey:#"type"];
if (type)
{
if ([type isEqualToString:#"OAuthException"]) //aha!
{
//user has unauthorized the app, lets logout from Facebook connect. Also clear the access and expiration date tokens
[facebook logout:self];
//Call the authorize method again. Or let the user know they need to authorize the app again.
}
}
}
So, as I said before, not the best way, but gets the job done. Hopefully, Facebook will add a method to check for this specific scenario, or add a new method to the delegate that deals with the unauthorized app issue.
I'm not sure how exactly to do it with Facebook's SDK, but you can use FQL to query the permissions. The query URL would look something like
https://api.facebook.com/method/fql.query?query=SELECT+uid,+read_stream,+offline_access+FROM+permissions+WHERE+uid=me()&access_token=...
It looks like requestWithMethodName:andParams:andHttpMethod:andDelegate: passing fql.query as the method is the way to go, as long as you can arrange for isSessionValid to be true (or somehow supply access_token in the params yourself).

How to gey Sessionkey from new FaceBook SDK in iphone

Can any one help me in this:
I used new FaceBook SDK, and there is no Session seen any where. How can we get Session key after logging in to Facebook.
Im using '- (void)fbDidLogin;' method after login to facebook.
Thanks in advance
Assuming you are using the Facebook connect api. You'd have to create a FBSession object and initialize in either initWithNibName or ViewDidLoad. This object automatically gets populated with the session key once the user has been authenticated.
FBSession *session = [[FBSession sessionForApplication:#"bla bla" secret:#"bla bla"
delegate:self]retain];

Impossible issue connecting to Windows Live Messenger network

This issue is giving me serious headaches, I don't have a clue what's going on here. If you don't have any experience with the Windows Live network, I ask you to read this anyway, maybe it has nothing to do with it and am I overlooking something totally unrelated.
In short: I wrote an Objective-C class that allows me to connect to the Windows Live Messenger network, called WLNotificationSession. I works really straightforward, I set the username and password variables and do [notificationSession start];. It then logs in successfully.
Let's say I have two Windows Live accounts. The first one, A, is now logged in.
The problem arises when I try to fire up a second WLNotificationSession, with the other Windows Live account, B. It always fails. The usernames and passwords are 100% correct. When I try to log in B first, it succeeds. When I try A while B is logged in, it fails. The second login session always fails.
It can't be something like "too much log in attempts in a short period of time". When I log in A, quit the app, restart the app and log in A again, both attempts succeed. I can do this within 20 seconds. But, when I fire up the app, log A in, disconnect A, wait 2 hours, log in B (all without closing the app), it fails. (??)
For those of you with experience with the WL network: the failure occurs during the Tweener authentication. The part where you get the "Authentication-Info" or "WWW-Authenticate" HTTP header from the login server. When it fails, I get this value:
"Www-Authenticate" = "Passport1.4 da-status=failed-noretry,srealm=Passport.NET,ts=-2,prompt,cburl=http://messenger.msn.com/images/logo102x88.gif,cbtxt=.NET%20Messenger%20Service";
I really hope someone can help with this. Thank you.
UPDATE
This is some example code. I create a new project, add this code in the applicationDidFinishLaunching method and click Build & Run:
WLNotificationSession *notificationSession1 = [[WLNotificationSession alloc] init];
notificationSession1.username = #"testaccount1#hotmail.com";
notificationSession1.password = #"testpwd";
[notificationSession1 start];
WLNotificationSession *notificationSession2 = [[WLNotificationSession alloc] init];
notificationSession2.username = #"testaccount2#hotmail.com";
notificationSession2.password = #"testpwd";
[notificationSession2 start];
notificationSession1 always succeeds, notificationSession2 always fails. No global variables, or shared variables whatsoever.
UPDATE 2
Following David's suggestion the problem could be cookie-related, I added this code to my project:
[[NSHTTPCookieStorage sharedHTTPCookieStorage] setCookieAcceptPolicy:NSHTTPCookieAcceptPolicyNever];
I also use his method in the comments below to delete any cookies before and after each URL request. This is probably unnecessary, but I do it anyway.
I think at this point it is safe to assume it's not the cookies, or there has to be some other place where cookies are stored.
No global variables, or shared variables whatsoever
Then, as the authentication is performed using http request, this could be cookie issue. There might be some session cookie reminding the server about the former session.
I know that FBConnect (Facebook API for iPhone) uses the following method when logging out to remove any cookie :
- (void)deleteFacebookCookies {
NSHTTPCookieStorage* cookies = [NSHTTPCookieStorage sharedHTTPCookieStorage];
NSArray* facebookCookies = [cookies cookiesForURL:[NSURL URLWithString:#"http://login.facebook.com"]];
for (NSHTTPCookie* cookie in facebookCookies) {
[cookies deleteCookie:cookie];
}
}
You could try this (replace facebook url with yours). You could even add some NSLogs to watch for these cookies.

Facebook Connect on iPhone question

When you use facebook connect on the iPhone do you have to use the supplied login button and login screen built into the framework? The reason I ask is because I'm also using twitter and I would like to have the same user experience when they log in to user as they have when they log in to facebook. So I can either replicate the login screen facebook connect uses for twitter or just not use the facebook connect login screen all together.
Login button: no. Login screen: yes. I added FB Connect integration to my FriendFeed app for iPhone, Stir, and skipped the login button. Instead, a user can choose a "Share on Facebook" button on a UIActionSheet and the app either displays a login screen or automatically posts a link depending on whether the user is authenticated.
Here's a code snippet for you. If the session is successfully resumed, then a method on your FBSession object's delegate will be called.
if (![fbSession resume]) {
FBLoginDialog* dialog = [[[FBLoginDialog alloc] initWithSession:fbSession] autorelease];
[dialog show];
}
- (void)session:(FBSession*)session didLogin:(FBUID)uid {
NSLog(#"Hooray, I'm logged in to Facebook!");
}
Apologies for being a little vague in my example above. To be honest, I find FBConnect to be a bit of a mystery and tried my best to implement it and get away from it as quickly as possible in my app. Let me know if you need more information and I'll put together a more-concrete answer.
Per the request below:
You can get an FBSession object with FBSession's +sessionForApplication:secret:delegate class method. You call -resume on the session object. If it returns YES, it'll immediately call your delegate's -session:didLogin: method, which is where you should put your FB-dependent actions. If it does not successfully -resume, then you need to create an FBLoginDialog, as seen in the code snippet above. Make sense? Let me know if you need more info