I am creating an app for Facebook and twitter integration using sharekit. That works fine. But now I want to retrieve the username and password for facebook login. I followed this link.
But I am not able to retrieve these..
I can't understand how can use that method and where can i use to retrieve username and password
Can you please guide me if you know.
First of all, you can't retrieve a user's Facebook password. Hopefully the reasons for this are obvious.
You can, however, retrieve the access token that your app is granted once you connect your app to a user's Facebook account using ShareKit.
As of this writing, I don't believe ShareKit makes the access token accessible directly, but there's an easy hack to retrieve it.
Step 1: Ensure that you're app is authorized to connect to Facebook
BOOL isConnected = [SHKFacebook isServiceAuthorized];
If you get isConnected == NO here, your UI should indicate that the user needs to connect to Facebook to use your sharing features.
Step 2: Get the access token in order to access the user's Facebook data
Assuming you got isConnected == YES in step 1
// Hack into ShareKit's user defaults
NSUserDefaults *defaults = [NSUserDefaults standardUserDefaults];
NSString *accessToken = [defaults valueForKey:#"kSHKFacebookAccessToken"];
Step 3: Bypass ShareKit and make a custom query to the Facebook SDK
Assuming a property in your class such as this one...
// Change "strong" to "retain" if not using ARC
#property (nonatomic, strong) SHKFacebook *shkFb;
...you can start a Facebook query with something like this...
if ( !fb ) {
// This is how SHKFacebook instantiates a Facebook object. YMMV.
self.fb = [[Facebook alloc] initWithAppId:SHKCONFIG(facebookAppId)];
}
NSMutableDictionary *fbParams = [NSMutableDictionary dictionaryWithObjectsAndKeys:
#"name", #"fields",
accessToken, #"access_token",
nil];
[fb requestWithGraphPath:#"me" andParams:fbParams andDelegate:self];
Step 4: Implement the Facebook delegate methods
Once the Facebook query's done, it'll notify your object, at which point you can do fancy things such as display the user's name to make it clear whose wall will get posts sent from your app.
You'll need to declare the FBRequestDelegate protocol in your .h, of course:
#import "Facebook.h"
#interface YourClass : NSObject <FBRequestDelegate>
And you'll need to implement (minimally) the success and failure methods from FBRequestDelegate:
#pragma mark - FBRequestDelegate
- (void)request:(FBRequest *)request didLoad:(id)result {
// Additional keys available in "result" can be found here:
// https://developers.facebook.com/docs/reference/api/user/
NSString *username = [result objectForKey:#"name"];
// Localize if you're at all interested in the global app market!
NSString *localizedString = NSLocalizedString(#"connected as %#",
#"Connection status label");
// The label will read "connected as <username>"
self.statusLabel.text = [NSString stringWithFormat:localizedString, username];
}
- (void)request:(FBRequest *)request didFailWithError:(NSError *)error {
// Handle failure
// (In our app, we call [SHKFacebook logout]
// and display an error message to the user with
// an option to retry connecting to Facebook.)
}
I believe clozach's answer is for an older version of ShareKit. In the most recent (as of Jan 30 2012) the method of acquiring the Facebook Access Token provided fails with accessToken always being nil.
// Hack into ShareKit's user defaults
NSUserDefaults *defaults = [NSUserDefaults standardUserDefaults];
NSString *accessToken = [defaults valueForKey:#"kSHKFacebookAccessToken"];
Instead, using
NSString *accessToken = [[FBSession activeSession] accessToken];
works for me.
ShareKit uses FBConnect internally for authentication. So the values can't be retrieved using the same method as you would for Twitter. FBConnect uses a UIWebView view to connect to the server while authenticating. After authentication, the app will store a token which can be reused to publish the text until the user discards the token on Facebook.
So, the answer is no. You can't get that data.
Related
Actually i want to upload photo on facebook fan page so for this i wrote below code
[m_facebook setAccessToken:#"BAAGgxy3PqqcBAHqByi2JOtTs .....8SCo8MK22y0smcFnxFEt7U6zVP2U4WpLrpnDWNuwXpvSYB9Btt7ZCMljBGmfxgPKoOdmadmNitSZB47trDv9hXd4wAE3VjZBbWBGMPP1lV8H1rfTcXNRuX8ePqRhxXsAypA7uHkSVyZASp0oaVfY0sJF55O8agZDZD"];
[m_facebook requestWithGraphPath:#"437...6356137/photos"
andParams:fbArguments
andHttpMethod:#"POST"
andDelegate:self];
With above code i am able to post photo on my facebook fan page but the problem is i have to hard code Page_Access_Token as you can see so can any one tell me that how i can access this Page_Access_Token token dynamically using FBConnect. I have already went through this link.
You have to authenticate by this line
NSArray *permissions = [[NSArray arrayWithObjects:#"read_stream", #"offline_access", #"publish_stream", #"manage_pages", #"user_photos", #"friends_photos",nil] retain];
[facebook authorize:FB_APP_ID permissions:permissions delegate:self];
Once you get authenticated , you will get AccessToken via this delegate method
- (void)fbDidExtendToken:(NSString*)accessToken expiresAt:(NSDate*)expiresAt
{
//Use access token
}
- (void)fbDidLogin {
[self.facebook1 accessToken];//you can access token once you get this call back.
}
Note: When you call extendAccessToken to extend token, the above delegate will call in that time too. fbDidLogin delegate method call when you get first time authentication. fbDidExtendToken delegate method get call when you try to extend access token. accessToken will get expired depending on expirationDate.
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?
How does my fb connect webserver authenticate a user that logged in via fb ios sdk? I have a website which uses facebook connect. In it, i do use the app secret to authenticate the user via a cookie created by the facebook javascript sdk via the facebook python library:
def get_user_from_cookie(cookies, app_id, app_secret):
"""Parses the cookie set by the official Facebook JavaScript SDK.
cookies should be a dictionary-like object mapping cookie names to
cookie values.
If the user is logged in via Facebook, we return a dictionary with the
keys "uid" and "access_token". The former is the user's Facebook ID,
and the latter can be used to make authenticated requests to the Graph API.
If the user is not logged in, we return None.
Download the official Facebook JavaScript SDK at
http://github.com/facebook/connect-js/. Read more about Facebook
authentication at http://developers.facebook.com/docs/authentication/.
"""
cookie = cookies.get("fbs_" + app_id, "")
if not cookie: return None
args = dict((k, v[-1]) for k, v in cgi.parse_qs(cookie.strip('"')).items())
payload = "".join(k + "=" + args[k] for k in sorted(args.keys())
if k != "sig")
sig = hashlib.md5(payload + app_secret).hexdigest()
expires = int(args["expires"])
if sig == args.get("sig") and (expires == 0 or time.time() < expires):
return args
else:
return None
Now, I'm wondering how to connect a user who logs in via the iphone to my website. Do I just send the access token over to my webserver and based on the the access token make a call to the graph(just bypass the above function)? If that is it, then what about all the validation the above function offers?
The cookie fetch and validation is useful for Google AppEngine or JavaScript SDK access.
For accessing user session initiated in iOS app, in Python SDK, just use:
graph = facebook.GraphAPI(access_token)
user = graph.get_object("me")
Hope that helps.
If you want use Facebook iOS API you need:
Alloc and Init a Facebook object
Facebook *facebookObject = [[Facebook alloc] init];
Check permissions
NSArray *permissions = [NSArray arrayWithObjects:#"publish_stream", #"offline_access",nil];
Authorize facebook
[facebookObject authorize:APP_ID permissions:permissions delegate:self];
After that you can used NSUserDefaults to keep session like that :
To store session I use NSUserDefaults.
[[NSUserDefaults standardUserDefaults] setObject:facebookObject.accessToken forKey:#"AccessToken"];
[[NSUserDefaults standardUserDefaults] setObject:facebookObject.expirationDate forKey:#"ExpirationDate"];
[[NSUserDefaults standardUserDefaults] synchronize];
After that I can catch Access with :
facebookObject.accessToken = [[NSUserDefaults standardUserDefaults] stringForKey:#"AccessToken"];
facebookObject.expirationDate = (NSDate *) [[NSUserDefaults standardUserDefaults] objectForKey:#"ExpirationDate"];
Like that you can keep session alive and the user enter login and password only once. I think that is why cookies.
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.
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)