iPhone / iOS Facebook SDK - can you log in within the app, and keep the login credentials? - iphone

Is it possible to use the Facebook iOS SDK to authenticate within an app (not go to Safari), and also keep those authentication credentials for the next launch of the app?
When I try to use the demo app in the simulator, it always goes to safari to authenticate, which seems a bit crappy. And then, when I authenticate... if I completely kill the app it will ask to authenticate again (and then tell me I am already logged in)
Is there a way, to just present the user with just an email field and a password field and then keep that info.. within the app?

Take a look at this question and answer: Iphone facebook connect example calls safari. I don't want to use safari. Also, you'll want to store the authentication stuff in NSUserDefaults and check for them to make to prevent re-logins.
EDIT Some sample code:
To save login stuff:
[[NSUserDefaults standardUserDefaults] setObject:_facebook.accessToken forKey:#"AccessToken"];
[[NSUserDefaults standardUserDefaults] setObject:_facebook.expirationDate forKey:#"ExpirationDate"];
[[NSUserDefaults standardUserDefaults] synchronize];
To check for login stuff:
_facebook = [[[Facebook alloc] initWithAppId:#"[app_id]"] retain];
_facebook.accessToken = [[NSUserDefaults standardUserDefaults] stringForKey:#"AccessToken"];
_facebook.expirationDate = (NSDate *) [[NSUserDefaults standardUserDefaults] objectForKey:#"ExpirationDate"];
if (![_facebook isSessionValid]) {
[_facebook authorize:_permissions delegate:self];
}
else {
[_facebook requestWithGraphPath:#"me" andDelegate:self];
}

You can hack round it to stop it if this is what you really want, bearing in mind most other apps that migrate from the older Facebook connect api to graph will behave in the new way
In facebook.m find the following method
- (void)authorizeWithFBAppAuth:(BOOL)tryFBAppAuth
safariAuth:(BOOL)trySafariAuth
find the bottom of the didOpenOtherApp logic and comment out all above it so that it always opens inline and tuns this section of code thats contained in the !didOpenOtherApp braces
// If single sign-on failed, open an inline login dialog. This will require the user to
// enter his or her credentials.
if (!didOpenOtherApp) {
[_loginDialog release];
_loginDialog = [[FBLoginDialog alloc] initWithURL:loginDialogURL
loginParams:params
delegate:self];
[_loginDialog show];
}
However by doing this you are making it more likely that the user will have to input their credentials, which is surely worse than putting up with the fast app switching approach?

When you first auth, make sure you're asking for "offline_access" permission. That will make the token that OAuth returns to you NOT be invalidated at the end of the session, but instead stay valid literally until they come along and use the API to log your app OUT of Facebook.
Then, obviously, you need to save the token (I feel like NSUserDefaults is a fine place for it) and reuse it on later FB interactions.

Related

Problems with fbDidLogin never called iOS

I'm having problems with my app saving the access_token. The problem is, when an iPhone hasn't the Facebook app installed, safari will handle this and there is no problem. But as soon as the iPhone has the Facebook app installed. It Just isn't saving the access token and opens the Facebook app every time when it needs to do something with Facebook. It then says, you already have given .... permission...
This is what i'm doing to in the viewdidload to ask permission the first time and receive the access token from the user defaults:
facebook = [[Facebook alloc] initWithAppId:#"APPID"];
NSUserDefaults *defaults = [NSUserDefaults standardUserDefaults];
if ([defaults objectForKey:#"FBAccessTokenKey"]
&& [defaults objectForKey:#"FBExpirationDateKey"]) {
facebook.accessToken = [defaults objectForKey:#"FBAccessTokenKey"];
facebook.expirationDate = [defaults objectForKey:#"FBExpirationDateKey"];
}
NSArray* permissions = [[NSArray arrayWithObjects:
#"read_stream", #"offline_access", nil] retain];
if (![facebook isSessionValid]) {
[facebook authorize:permissions delegate:self];
}
This is what i'm doing in the fbdidlogin:
- (void)fbDidLogin {
NSUserDefaults *defaults = [NSUserDefaults standardUserDefaults];
[defaults setObject:[facebook accessToken] forKey:#"FBAccessTokenKey"];
[defaults setObject:[facebook expirationDate] forKey:#"FBExpirationDateKey"];
[defaults synchronize];
}
But for some way when the Facebook app takes control this just doesn't work...It wil doe authorize every time when the view did load, loads again.
Has anyone got a clue?
Thnx!
btw: I also have the following line:
(BOOL)application:(UIApplication *)application handleOpenURL:(NSURL *)url { return [[controller facebook] handleOpenURL:url]; }
I just had this problem and believe I may have found your solution. When you create the app on facebook you must edit your app settings to allow for native ios app. The ios bundle id selected must match EXACTLY to your bundle ID in the app you are creating. Facebook states that they check this prior to authorizing your app. Funny thing is if you remove the facebook app from the device and then try to authenticate it uses the web browser and seemingly bipasses this "security" completely. This is why Jos solution "works". Facebook doesn't send an error message back so it was a lot of fun to track down. I figured I'd throw this answer out there in hopes to save some future devs some trouble. I hope this helps.
Have you disabled multi-task on your app via Info.plist? The Facebook SDK makes the (undocumented assumption) that your app supports multi-task.
By that I mean you have a "Application does not run in background" (UIApplicationExitsOnSuspend) set to YES.
If that is the case, you're going to have to use login via an in-app browser for which I will update my post and provide a code sample.
I've found a workaround, which imo is better the using the Facebook app. In the Facebook.m file i've changed this:
[self authorizeWithFBAppAuth:YES safariAuth:YES];
to this
[self authorizeWithFBAppAuth:NO safariAuth:YES];
In this case users don't leave the app, and everything is handled within the popup without using the Facebook app.
That's what it does now. It bails out to the Facebook app if it's installed, or to Safari if it's not. You can explicitly use the dialog interface, but the simplest sample code supplied with the library does its auth business by leaving your app, then coming back after the FB app has handled auth. It works okay, and once you have your head around it (and have it configured properly to return to you), it's fine.
To prevent re-authentication on each session, request the permission token "offline_access".
Double check your controller reference in the handleOpenURL: method on your app delegate. I get the feeling that it may be setting to nil in the background, so Facebook never receives the response.
The lines:
[self authorizeWithFBAppAuth:YES safariAuth:YES];
being changed to
[self authorizeWithFBAppAuth:NO safariAuth:YES];
is possible only when we have access to Facebook.m (since that's where one would have to make a change)
In case we're using Facebook's latest static library, we don't get access to the the .m file. In that case how would we be able to achieve the same functionality?

YAFBLQ: How to pre-populate FB login and password fields?

Yet another fb login question:
By the time my user has something to share, they've already logged into my app server.
I give them the option to use their FB creds for my app.
So if they share, I want to pre-populate the FB login page with the creds they've already supplied to me.
Does anyone know if this is possible, and if so, how to do it?
Here's what I'm talking about:
I use Facebook API too. You never keep login and pass in your app (check Facebook API doc). However you can keep session. So the user enter login and pass once. In my code I've a "FacebookLogger" who is a singleton with a Facebook object.
To store session I use NSUserDefaults (find doc here).
[[NSUserDefaults standardUserDefaults] setObject:m_Facebook.accessToken forKey:#"AccessToken"];
[[NSUserDefaults standardUserDefaults] setObject:m_Facebook.expirationDate forKey:#"ExpirationDate"];
[[NSUserDefaults standardUserDefaults] synchronize];
Where m_Facebook is my Facebook object in my singleton. After that I can catch Access with :
m_Facebook.accessToken = [[NSUserDefaults standardUserDefaults] stringForKey:#"AccessToken"];
m_Facebook.expirationDate = (NSDate *) [[NSUserDefaults standardUserDefaults] objectForKey:#"ExpirationDate"];

Facebook Connect for iOS auto signs out after quitting app

I have implemented Facebook Connect in my app, and it seems to work fine. I can publish statuses and everything. However, when I quit the app and run it again, the session token seems to have expired or something, because I can't post anymore. But if I authenticate with Facebook again, it shows that permissions have already been granted, then only when the callback to the app is called, can I post again.
What am I doing wrongly?
you should store the accessToken and expireTime of your Facebook object yourself. Restore it after startup and verify via isSessionValid, otherwise reauthorize user. You can use these functions for it:
Call the store function within your fbDidLogin, and the restore function whenever it is appropriate after startup of your app.
-(void)restoreFBAccessToken {
self.facebook.accessToken = [[NSUserDefaults standardUserDefaults] objectForKey:#"fb_accessToken"];
self.facebook.expirationDate = [[NSUserDefaults standardUserDefaults] objectForKey:#"fb_expirationDate"];
}
-(void)storeFBAccessToken {
[[NSUserDefaults standardUserDefaults] setValue:self.facebook.accessToken forKey:#"fb_accessToken"];
[[NSUserDefaults standardUserDefaults] setValue:self.facebook.expirationDate forKey:#"fb_expirationDate"];
[[NSUserDefaults standardUserDefaults] synchronize];
}
I'm also using FB Connect in my own app, but in an indirect way. I use it through a third-party open source kit named ShareKit. http://www.getsharekit.com/
As I remember, ShareKit does the job pretty well. It remembers those login information even though the app is shut down.
Since ShareKit is open-source, I suggest you take a look at its code. It should have an answer for you. :-)
Have you made sure to start the session once again when the app is reloaded up?

logout from Twitter in iPhone using OAuth+MGTwitterEngine Library

I had made the twitter application using the OAuth and MGTwitterEngine Library. The login phase is working fine but I am facing problem in logout. I had referred all the post of logout for OAuth but it doesn't works. So can anyone suggest the perfect method for logout from the Twitter ...? OR What changes I have to make in the Library file for the logout..!!
Did anyone ever find the solution for this? If so, please post!
UPDATE: I figured it out. In the MGTwitterEngine.m, search for _clearCookies in initWithDelegate method. This is currently set to NO, change it to YES. In your action method for logging out the current user, call [_engine clearAccessToken]. Now run it, and voila, it works!
There is no sign out from Twitter OAuth/xAuth... you need to implement client side solution:
persistently store the access token in the keychain or coredata (it never expires unless the user revoke your application from his/her account) when log in and use it in subsequent calls to twitter and " keeping the user signed in"
when signing out delete any related data stored (in this case the access token)
hope that will help
I dont know how to logout. But if you want the login screen every time, do one thing (i dont know this is the right way), delete the login specific data which the engine saves in Userdefaults.
I don't see it explicitly stated here, but I used the "clearAccessToken" function in the SA_OAuthTwitterEngine to "log out" the current user.
Might be kinds of stupid, but this seems to work
- (IBAction)logout:(id)sender {
[_engine dealloc];
NSUserDefaults *defaults = [NSUserDefaults standardUserDefaults];
[defaults removeObjectForKey:#"authData"];
[defaults synchronize];
[self presentLoginView];
}
I use this tutorial for integreate twitter to iOS app link
For logout I use next:
[_engine clearAccessToken];
_engine - this is instance of SA_OAuthTwitterEngine class.
You can call this method on your IBAction method.
Also need this method
NSUserDefaults *defaults = [NSUserDefaults standardUserDefaults];
[defaults removeObjectForKey:#"authData"];
[defaults synchronize];
You must delete your account in Twitter application which is in the Settings menu of your iPhone.

Reading cookies using xcode on the iphone [duplicate]

Can an iPhone application read cookies previously stored by Safari Mobile?
To actually answer your question:
No.
Mobile Safari's cookies are not accessible from SDK apps. And each SDK app is given its own WebKit cache and cookie stores, so while cookies will persist within the same app, they aren't accessible betweeen apps.
As of iOS 9 this is possible!
Use a sfSafariViewController.
You will need to setup:
A custom URL scheme in your app to receive cookie data.
The website you are getting cookies from will need to implement an API specific your app's custom URL scheme, to redirect back to your app.
You can clone this repo which has a fully working demo of this.
Hope this helps,
Liam
There is actually an interesting way if you have access to a server url.
In your app launch the server url with mobile safari.
The target server url reads the cookie and redirects back to an app specific url (myapp://cookie=123)
The app is then switched back and you can read that value from the url handler
It's a little hacky as the app would switch mobile safari and then immediately switch back to the app. But, it is possible.
Note that on iOS 8, you're probably better using Safari Password Sharing to solve some of the use cases that give rise to this problem.
This is not directly possible, but with the cooperation of the web site it is possible.
To clarify, the user case is that an Objective C application wants to read the value of a cookie that has been set by a website in mobile safari. (ie. in particular, a UIWebView was not involved in setting the cookie)
Your app should do this:
Launch mobile safari, using [[UIApplication sharedApplication] openURL:url];
The URL should be a special one, eg. http://yourwebsite.com/give-ios-app-the-cookie
On your website, when that url is launched, issue a redirect to your-app-url-scheme:cookievalue= (eg. angrybirds:cookievalue=hh4523523sapdfa )
when your app delegate receives - (BOOL)application:(UIApplication *)application openURL:(NSURL *)url sourceApplication:(NSString *)sourceApplication annotation:(id)annotation process the url to get the cookie value
Note that you should not do this automatically when the application starts - the user will see the transfer to Mobile Safari and back, which is not a good user experience and Apple will reject your app (Apple also consider this to be "uploading user's personal data to server without their prior consent"). It would be better to do it in response to the user, paying attention to the user experience - eg. wait for the user to hit a "login" button, then do it, and if the user is not logged into your website, http://yourwebsite.com/give-ios-app-the-cookie should show the user the login screen within safari. If the user is logged in you could briefly show a "Automatically logging you in..." screen for a second or two in Safari before redirecting the user back.
There's no way to get this to work with hotmail/gmail/etc of course - it needs to be your own website.
Credit goes to Unique Identifier for both mobile safari and in app in iOS for suggesting this kind of approach.
Because of sandboxing on the iPhone you don't have access to Safari's cookies. You can only access cookies created within your application - by an UIWebView for example.
Although you have asked the same question twice before, here's one approach not yet mentioned...
This may be a little convoluted, but you can do Greasemonkey-esque things with a UIWebView. Something like this:
Load your target page
craft some javascript which will read the document.cookie and return the data you need
In the webViewDidFinishLoad delegate, inject this javascript into the UIWebView with the stringByEvaluatingJavaScriptFromString message
I've used this technique to enhance 3rd party pages in an iPhone app, but I'm not sure if it will read cookies from the same place as Safari mobile.
Worth a shot though?
Here's my utils get/set cookie methods.
+(void)setCookie:(NSString *)key withValue:(NSString *)value {
NSArray *keys = [NSArray arrayWithObjects:
NSHTTPCookieDomain,
NSHTTPCookieExpires,
NSHTTPCookieName,
NSHTTPCookiePath,
NSHTTPCookieValue, nil];
NSArray *objects = [NSArray arrayWithObjects:
#"YOURDOMAIN",
[NSDate distantFuture],
key,
#"/",
value, nil];
NSDictionary *dict = [NSDictionary dictionaryWithObjects:objects forKeys:keys];
NSHTTPCookie *cookie = [NSHTTPCookie cookieWithProperties:dict];
NSHTTPCookieStorage *sharedHTTPCookieStorage = [NSHTTPCookieStorage sharedHTTPCookieStorage];
[sharedHTTPCookieStorage setCookie:cookie];
}
+(NSString *)getCookie:(NSString *)key {
NSHTTPCookieStorage *sharedHTTPCookieStorage = [NSHTTPCookieStorage sharedHTTPCookieStorage];
NSArray *cookies = [sharedHTTPCookieStorage cookiesForURL:[NSURL URLWithString:#"YOURDOMAIN"]];
NSEnumerator *enumerator = [cookies objectEnumerator];
NSHTTPCookie *cookie;
while (cookie = [enumerator nextObject])
{
if ([[cookie name] isEqualToString:key])
{
return [cookie value];
}
}
return nil;
}
You might want to check
if ([[NSHTTPCookieStorage sharedHTTPCookieStorage] cookieAcceptPolicy] != NSHTTPCookieAcceptPolicyAlways) {
[[NSHTTPCookieStorage sharedHTTPCookieStorage] setCookieAcceptPolicy:NSHTTPCookieAcceptPolicyAlways];
}
But apparently NSHTTPCookieStorage does not even hold cookies from the last request in the current application on iOS (rdar://8190706)