How to handle the FBSDK token expired case? - ios

I'm not sure how to handle the case when the iOS FBSDK is returning me an expired Token. In my app i'm calling the following method when clicking on a 'login'-button.
FBSDKLoginManager *login = [[FBSDKLoginManager alloc] init];
[login logInWithReadPermissions:#[#"public_profile", #"email", #"user_photos", #"user_birthday"]
fromViewController:nil
handler: etc.... ]
This then triggers a FBSDKAccessTokenDidChangeNotification, and I'm handeling this method as follows:
- (void)fbAccessTokenDidChange:(NSNotification *)notification
{
if ([notification.name isEqualToString:FBSDKAccessTokenDidChangeNotification]) {
FBSDKAccessToken* oldToken = [notification.userInfo valueForKey: FBSDKAccessTokenChangeOldKey];
FBSDKAccessToken* newToken = [notification.userInfo valueForKey: FBSDKAccessTokenChangeNewKey];
NSLog(#"FB access token did change notification\nOLD token:\t%#\nNEW token:\t%#", oldToken.tokenString, newToken.tokenString);
// initial token setup when user is logged in
if (newToken != nil && oldToken == nil)
{
NSDate *nowDate = [NSDate date];
NSDate *fbExpirationDate = [FBSDKAccessToken currentAccessToken].expirationDate;
if ([fbExpirationDate compare:nowDate] != NSOrderedDescending)
{
NSLog(#"FB token: expired");
if ([FBSDKAccessToken currentAccessToken])
{
[[FBSDKLoginManager new] logOut];
[[NSNotificationCenter defaultCenter] postNotificationName:#"fbTokenExpired" object:nil];
}
return;
}
[self storeFacebookToken];
}
else if (newToken && oldToken && ![oldToken.tokenString isEqualToString:newToken.tokenString])
{
NSLog(#"FB access token string did change");
[self storeFacebookToken];
}
}
}
What do I need to do for the caase that the token is expired??? I'm calling [[FBSDKLoginManager new] logOut] which sets the current token to nil. However when I redirect the user again to the login button action, the same window appears asking the user to press 'allow'. It is not asking the user to enter his password and email, which from my understanding would make a new token? Where am I missing the point? For now the user just goes in loops never loggin in...
Any help MUCH appreciated! Thnx

Logout In Your Facebook app in device. In simulator go to setting and Facebook logout
Or Safari browser facebook logout
Again Clean the project And run. It will ask to again login in you app.

Related

ParseFacebookUtils login issue

I'm building an app using Parse SDK and Facebook SDK. I'm using ParseFacebookUtils to log into the user's account with a token that is accessed like so:
- (void)viewDidAppear:(BOOL)animated {
[super viewDidAppear:YES];
if (![FBSDKAccessToken currentAccessToken])
{
// User is not logged in
[self performSegueWithIdentifier:#"LoginSegue" sender:self];
} else
{
// Have token, log in with it
[PFFacebookUtils logInInBackgroundWithAccessToken:[FBSDKAccessToken currentAccessToken] block:^(PFUser *user, NSError *error) {
if (!user)
{
// Error logging in
NSLog(#"error");
} else
{
// Logged in
NSLog(#"success!");
}
}];
}
}
This works, and the user is signed in. This happens automatically (first app launch uses logInInBackgroundWithReadPermissions: instead).
However, when I log the user out using
[[FBSDKLoginManager new] logOut];
The user is logged out (it appears like), but the token is retrieved during the next app launch, despite logging out - hence authenticating the user again.
I've tried to manually set the currentAccessToken like this - after calling logOut, but with the same result:
[FBSDKAccessToken setCurrentAccessToken:nil];
Why is this?
[FBSession.activeSession closeAndClearTokenInformation];
FBSDKLoginManager *login = [[FBSDKLoginManager alloc] init];
[login logOut];

Check if accesstoken is expired Facebook SDK 4.7 ios

I am using facebook sdk 4.7 and I need to check if accesstoken is expired.
FBSDKAccessToken *access_token = [FBSDKAccessToken currentAccessToken];
if (access_token != nil) {
//user is not logged in
//How to Check if access token is expired?
if ([access_token isExpired]) {
//access token is expired ......
//
}
}
And if I success with that I have to log the user again.
The SDK gives an expiration_date.how can that help? The device may have wrong date.
Assuming user has been logged in with Facebook before and has [FBSDKAccessToken currentAccessToken] != nil(I am not going into details here, because login via FB is another story).
In my app, I do the following to make sure the FB access token is always valid and synced with my app server.
To keep it simple, all the code below is in AppDelegate.m
- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions
{
// ...
/**
Add observer BEFORE FBSDKApplicationDelegate's
application:didFinishLaunchingWithOptions: returns
FB SDK sends the notification at the time it
reads token from internal cache, so our app has a chance
to be notified about this.
*/
[[NSNotificationCenter defaultCenter] addObserver:self
selector:#selector(fbAccessTokenDidChange:)
name:FBSDKAccessTokenDidChangeNotification
object:nil];
return [[FBSDKApplicationDelegate sharedInstance] application: application didFinishLaunchingWithOptions: launchOptions];
}
- (void)fbAccessTokenDidChange:(NSNotification*)notification
{
if ([notification.name isEqualToString:FBSDKAccessTokenDidChangeNotification]) {
FBSDKAccessToken* oldToken = [notification.userInfo valueForKey: FBSDKAccessTokenChangeOldKey];
FBSDKAccessToken* newToken = [notification.userInfo valueForKey: FBSDKAccessTokenChangeNewKey];
NSLog(#"FB access token did change notification\nOLD token:\t%#\nNEW token:\t%#", oldToken.tokenString, newToken.tokenString);
// initial token setup when user is logged in
if (newToken != nil && oldToken == nil) {
// check the expiration data
// IF token is not expired
// THEN log user out
// ELSE sync token with the server
NSDate *nowDate = [NSDate date];
NSDate *fbExpirationDate = [FBSDKAccessToken currentAccessToken].expirationDate;
if ([fbExpirationDate compare:nowDate] != NSOrderedDescending) {
NSLog(#"FB token: expired");
// this means user launched the app after 60+ days of inactivity,
// in this case FB SDK cannot refresh token automatically, so
// you have to walk user thought the initial log in with FB flow
// for the sake of simplicity, just logging user out from Facebook here
[self logoutFacebook];
}
else {
[self syncFacebookAccessTokenWithServer];
}
}
// change in token string
else if (newToken != nil && oldToken != nil
&& ![oldToken.tokenString isEqualToString:newToken.tokenString]) {
NSLog(#"FB access token string did change");
[self syncFacebookAccessTokenWithServer];
}
// moving from "logged in" state to "logged out" state
// e.g. user canceled FB re-login flow
else if (newToken == nil && oldToken != nil) {
NSLog(#"FB access token string did become nil");
}
// upon token did change event we attempting to get FB profile info via current token (if exists)
// this gives us an ability to check via OG API that the current token is valid
[self requestFacebookUserInfo];
}
}
- (void)logoutFacebook
{
if ([FBSDKAccessToken currentAccessToken]) {
[[FBSDKLoginManager new] logOut];
}
}
- (void)syncFacebookAccessTokenWithServer
{
if (![FBSDKAccessToken currentAccessToken]) {
// returns if empty token
return;
}
// BOOL isAlreadySynced = ...
// if (!isAlreadySynced) {
// call an API to sync FB access token with the server
// }
}
- (void)requestFacebookUserInfo
{
if (![FBSDKAccessToken currentAccessToken]) {
// returns if empty token
return;
}
NSDictionary* parameters = #{#"fields": #"id, name"};
FBSDKGraphRequest *request = [[FBSDKGraphRequest alloc] initWithGraphPath:#"me"
parameters:parameters];
[request startWithCompletionHandler:^(FBSDKGraphRequestConnection *connection, id result, NSError *error) {
NSDictionary* user = (NSDictionary *)result;
if (!error) {
// process profile info if needed
}
else {
// First time an error occurs, FB SDK will attemt to recover from it automatically
// via FBSDKGraphErrorRecoveryProcessor (see documentation)
// you can process an error manually, if you wish, by setting
// -setGraphErrorRecoveryDisabled to YES
NSInteger statusCode = [(NSString *)error.userInfo[FBSDKGraphRequestErrorHTTPStatusCodeKey] integerValue];
if (statusCode == 400) {
// access denied
}
}
}];
}
Each time you think it is good time to check FB token (e.g. an app was in background for a while), call -requestFacebookUserInfo. This will submit Open Graph request and returns an error if token is invalid/expired.
for checking facebook permission..& give a permission...if permission exist then automatically get accesstoken other wise ask for login...
For Swift
var login: FBSDKLoginManager = FBSDKLoginManager()
login.logInWithReadPermissions(["public_profile", "email"], handler: { (result:FBSDKLoginManagerLoginResult!, error:NSError!) -> Void in
if (error != nil)
{
//Process error
}
else if result.isCancelled
{
//Handle cancellations
}
else
{
// If you ask for multiple permissions at once, you
// should check if specific permissions missing
if result.grantedPermissions.contains("email"){
//Do work
}
}
})
For Objective c:
check Permission like this. following code use ..
if ([[FBSDKAccessToken currentAccessToken]hasGranted:#"email"])
{
// add your coding here after login call this block automatically.
}
else
{
//login code **//if accesstoken expired...then call this block**
FBSDKLoginManager *loginManager = [[FBSDKLoginManager alloc] init];
[loginManager logInWithReadPermissions:#[#"public_profile", #"email"] handler:^(FBSDKLoginManagerLoginResult *result, NSError *error)
}];
}

ios non-Dialog Facebook share fails with no errors and no feedback

I have had facebook sharing working fine in my ios app for a year and have upgraded (aka totally rewritten) to use the latest api (4.7.x) and now sharing doesnt work at all. I check that I have publish_actions permission (which I do prior to this method being called, I have 'expicitly shared' checked in open graph settings, action types, capabilities. I am validating the content (I dont get an error) and have a delegate, none of its methods get called.
-(void)shareWithFacebook:(NSString *)message
{
if ([[FBSDKAccessToken currentAccessToken] hasGranted:#"publish_actions"])
{
NIDINFO(#"Facebook sharing has publish_actions permission");
}
else
{
FBSDKLoginManager *loginManager = [[FBSDKLoginManager alloc] init];
[loginManager logInWithPublishPermissions:#[#"publish_actions"]
handler:^(FBSDKLoginManagerLoginResult *result, NSError *error)
{
NIDERROR(#"Facebook sharing getting publish_actions permission failed: %#", error);
}
];
}
NSMutableDictionary *properties = [NSMutableDictionary dictionaryWithDictionary: #{
#"og:type": #"article",
#"og:title": #"Bloc",
#"og:description": message,
#"og:url": #"http://getonbloc.com/download"
}];
FBSDKShareOpenGraphObject *object = [FBSDKShareOpenGraphObject objectWithProperties:properties];
// Create the action
FBSDKShareOpenGraphAction *action = [FBSDKShareOpenGraphAction actionWithType:#"mynamespace:Share" object:object key:#"article"];
[action setString:#"true" forKey:#"fb:explicitly_shared"];
// Create the content
FBSDKShareOpenGraphContent *content = [[FBSDKShareOpenGraphContent alloc] init];
content.action = action;
content.previewPropertyName = #"article";
// Share the content
FBSDKShareAPI *shareAPI = [[FBSDKShareAPI alloc] init];
shareAPI.shareContent = content;
shareAPI.delegate = self;
NSError *error;
if([shareAPI validateWithError:&error] == NO)
{
NIDERROR(#"Facebook sharing content failed: %#", error);
}
[shareAPI share];
}
#pragma mark - FBSDKSharingDelegate
- (void) sharer:(id<FBSDKSharing>)sharer didCompleteWithResults:(NSDictionary *)results
{
NIDINFO(#"Facebook sharing completed: %#", results);
}
- (void) sharer:(id<FBSDKSharing>)sharer didFailWithError:(NSError *)error
{
NIDERROR(#"Facebook sharing failed: %#", error);
}
- (void) sharerDidCancel:(id<FBSDKSharing>)sharer
{
NIDINFO(#"Facebook sharing cancelled.");
}
I have login working and can get photos fine. I don't get any feedback at all from the facebook api, nothing gets posted. Am I doing something particularly stupid here?
Just a possibility, but I find that Facebook integration has become inconvenient because I find that every time I check the current token for granted permission through hasGranted:, it almost always fail even though I gained permission a few minutes ago, or from a previous app launch.
It seems that in your code, if no permission is granted, you try to login and get the permission again. But when that block returns, regardless whether the actual permission is granted or not, you throw an error. Instead, you should continue with sharing if it is successful.

FBSDKLoginManager not handling logInWithPublishPermissions: correctly

I'm implementing v4.1 of the SDK for iOS and when I try to call for publishPermissions:, I get no callback.
For some reason everything works perfectly when I run logInWithReadPermissions:, but when I run logInWithPublishPermissions: it never hits my response handler. Nothing happens.
To test things out, I reset my loginManager before running logInWithPublishPermissions:, and to my surprise it worked then (aka NSLog(#"RESULT") is called).
Am I missing something about how the loginManager works? Shouldn't I be able to use it without resetting it?
// FacebookController.m
#implementation FacebookController
FBSDKLoginManager *loginManager;
static FacebookController *_shared = nil;
- (id)init {
self = [super init];
if (self != nil) {
userData = [[NSMutableDictionary alloc] init];
loginManager = [[FBSDKLoginManager alloc] init];
}
return self;
}
+ (id)getInstance {
if (!_shared) {
_shared = [[self alloc] init];
}
return _shared;
}
- (bool)hasPublishPermissions {
FBSDKAccessToken *accessToken = [FBSDKAccessToken currentAccessToken];
if(accessToken != NULL){
NSSet *permissions = [accessToken permissions];
if([permissions containsObject:#"publish_actions"]){
return TRUE;
}
}
return FALSE;
}
- (void)requestPublishPermissionsWithDelegate:(id)aDelegate {
if(![self hasPublishPermissions]){
// FOR SOME REASON IT WORKS IF I RESET LOGIN MANAGER AS FOLLOWS
// loginManager = [[FBSDKLoginManager alloc] init];
[loginManager logInWithPublishPermissions:#[#"publish_actions"] handler:^(FBSDKLoginManagerLoginResult *result, NSError *error) {
NSLog(#"RESULT: %#", result);
}];
}
}
- (void)connectToFacebookWithDelegate:(id)aDelegate {
FBSDKAccessToken *accessToken = [FBSDKAccessToken currentAccessToken];
if(accessToken != nil){
[aDelegate performSelector:#selector(facebookSignedIn)];
} else {
[loginManager logInWithReadPermissions:#[#"email"] handler:^(FBSDKLoginManagerLoginResult *result, NSError *error) {
if (error) {
// Process error
NSLog(#"ERROR");
} else if (result.isCancelled) {
// Handle cancellations
NSLog(#"CANCELLED");
} else {
NSLog(#"SUCCESS");
[aDelegate performSelector:#selector(facebookSignedIn)];
}
}];
}
}
#end
Edit #1:
Including videos of it working and not working for the given scenarios:
Not working (loginManager reinitialization commented out):
https://dl.dropboxusercontent.com/u/14277258/not-working.mov
Working (loginManager reinitialized):
https://dl.dropboxusercontent.com/u/14277258/working.mov
Your video stack trace indicates you're calling the request for publish permissions inside the handler for your initial login. This should be avoided:
You're causing another login after the user has already granted you some permissions - it's not very good for the user to have to see another login dialog immediately after completing one.
You're asking for publish permissions when you don't need it - this may violate Facebook developer policies and again is not the best user experience. Instead you should asking for publish only when you need it (i.e., at the time of sharing).
If you really insist, you can dispatch your second login call asynchronously so that the first request finishes entirely but I wouldn't recommend it. We can probably update the SDK to detect this and log though so it's not as confusing.

Check if logged in on ios facebook sdk 3.0

I am using iOS facebook SDK 3.0. How can i check if the user is already logged in?
I tried the line below but it does not work properly. It sometimes returns NO although I am logged in. Any suggestions?
if (FBSession.activeSession.isOpen == YES)
{
// post to wall else login
}
-- EDIT --
this is how I open my Facebook session:
NSArray *permissions = [[NSArray alloc] initWithObjects:
#"user_likes",
#"read_stream",
#"publish_actions",
nil];
return [FBSession openActiveSessionWithPermissions:permissions
allowLoginUI:allowLoginUI
completionHandler:^(FBSession *session,
FBSessionState state,
NSError *error) {
[self sessionStateChanged:session
state:state
error:error];
}];
The first time it needs login and so it works. If i try this while I am already logged in the FBSession.activeSession.isOpen returns NO.
You can check if you have a valid token by trying to open a new session without allowing the
login UI
if (FBSession.activeSession.isOpen)
{
// post to wall
} else {
// try to open session with existing valid token
NSArray *permissions = [[NSArray alloc] initWithObjects:
#"user_likes",
#"read_stream",
#"publish_actions",
nil];
FBSession *session = [[FBSession alloc] initWithPermissions:permissions];
[FBSession setActiveSession:session];
if([FBSession openActiveSessionWithAllowLoginUI:NO]) {
// post to wall
} else {
// you need to log the user
}
}
If you are using FBSDK greater then 4.x then there is no concept of FBSession. You have to find the active session only by using [FBSDKAccessToken currentAccessToken] simply check if it has nil value, no active session else it is.
Instead, you should check [FBSDKAccessToken currentAccessToken] at
viewDidLoad or similar. If a current token is available, do the
post-login work. You can also use currentAccessToken to retrieve
cached tokens.
you can find more here https://developers.facebook.com/docs/ios/upgrading-4.x
FBSession.activeSession has been replaced with [FBSDKAccessToken currentAccessToken] and FBSDKLoginManager. There is no concept of
session state. Instead, use the manager to login and this sets the
currentAccessToken reference.
i did it as in the Facebook example
if (FBSession.activeSession.state == FBSessionStateCreatedTokenLoaded)
{
}
The session is active if the state is either in FBSessionStateOpen or in FBSessionStateOpenTokenExtended. You can use the function below to check if the user is logged in:
- (BOOL)isSessionOpen
{
return FBSession.activeSession.state == FBSessionStateOpen || FBSession.activeSession.state == FBSessionStateOpenTokenExtended;
}
How are you opening your FBSession?
If you're creating an instance, be sure to set FBSession.activeSession. That was my issue for a while.
if ([FBSDKAccessToken currentAccessToken])
{
NSLog(#"Already login");
//[FBSession openActiveSessionWithAllowLoginUI: YES];
}

Resources