4

My app is iOS7 only, and in the interest of saving headaches I decided against using the Facebook SDK for authentication and instead rely on iOS's ACAccountStore. Unfortunately I'm still getting headaches.

I have a class called FacebookService with one method called login. I'll post the code below, but in general I do the standard dance of configuring an instance of ACAccountStore and then call requestAccessToAccountsWithType. In the completion block, if granted returns false I message the user and short-circuit.

If granted is true, then my code used to make the assumption that I had everything needed to obtain the user's oauthToken using the following code:

ACAccount *fbAccount = [[accountStore accountsWithAccountType:fbAccountType] lastObject];
ACAccountCredential *fbCredential = [fbAccount credential];
NSString *accessToken = [fbCredential oauthToken];

I get the oauthToken from the ACAccount#credential, and the first thing that's weird is that according to the documentation:

For privacy reasons, this property (is inaccessible after the account is saved.

I can definitely tell you that the majority of the time, this property is absolutely accessible and I can use it to send to my server to find a previously authenticated user.

However, a handful of times, the value will in fact be null. And in every case where this happens, it can be resolved if the user goes to Settings > Facebook > Turn our app off > Turn our app on. They go back to our app, tap "Sign in with Facebook" and everything works perfectly.

So here are my questions:

  1. Is there any way to consistently get a user's oauthToken from their FB ACAccount? As you'll see in my code, I now check first whether or not that value is empty, and if it is, I throw them an alert.
  2. What does it say that the user can fix this by going into Settings, disabling then enabling my app? Is their account out of sync or do I need to renew credentials?
  3. Is there a way to recover within the my method if I'm told that the access has been granted but I fail to receive an oauthToken?
  4. Does anybody know of a way I can set my system up so I can reliably reproduce this?

Here's my code:

- (void)login
{
    ACAccountStore *accountStore = [[ACAccountStore alloc] init];
    ACAccountType *fbAccountType = [accountStore accountTypeWithAccountTypeIdentifier:ACAccountTypeIdentifierFacebook];
    NSString *appId = [[Environment sharedInstance] fbAppId];

    NSDictionary *fbOptions = @{
        ACFacebookAppIdKey : appId,
        ACFacebookPermissionsKey : [@"email,user_birthday,user_hometown,user_location,user_photos" componentsSeparatedByString:@","],
        ACFacebookAudienceKey: ACFacebookAudienceEveryone
    };

    [accountStore requestAccessToAccountsWithType:fbAccountType options:fbOptions completion:^(BOOL granted, NSError *error) {
        NSString *message;
        NSString *title;

        if (!granted) {
            if (!error || error.code == ACErrorPermissionDenied) {
                title = @"AFAR Needs Your Permission";
                message = @"Your Facebook account is configured in Settings. Go to Settings and enable AFAR.";
            } else if (error.code == ACErrorAccountNotFound) {
                title = @"No Facebook Account";
                message = @"There are no Facebook accounts configured. You can add or create a Facebook account in Settings.";
            }

            if (message) {
                dispatch_async(dispatch_get_main_queue(), ^{
                    [[NSNotificationCenter defaultCenter] postNotificationName:AfarFacebookLoginDidNotSucceed object:nil];
                    [UIAlertView simpleAlertWithTitle:title message:message];
                });
            }

            return;
        }

        ACAccount *fbAccount = [[accountStore accountsWithAccountType:fbAccountType] lastObject];
        ACAccountCredential *fbCredential = [fbAccount credential];
        NSString *accessToken = [fbCredential oauthToken];

        if ([accessToken isEmpty]) {
            message = @"You need to allow AFAR access to your Facebook account. Please visit Settings > Facebook and look for the AFAR entry. Turn the AFAR setting off, then back on.";
            title = @"Problem Connecting to Facebook";

            dispatch_async(dispatch_get_main_queue(), ^{
                [[NSNotificationCenter defaultCenter] postNotificationName:AfarFacebookLoginDidNotSucceed object:nil];
                [UIAlertView simpleAlertWithTitle:title message:message];
            });

            return;
        }

        [SessionAPIService signInUsingFacebookToken:accessToken withBlock:^(NSError *error) {
            if (!error) {
                [[NSNotificationCenter defaultCenter] postNotificationName:AFARCurrentUserDidSignInNotificatioName object:nil];
            }
        }];
    }];
}
djibouti33
  • 12,102
  • 9
  • 83
  • 116
  • Check my answer here: https://stackoverflow.com/questions/17737667/acaccountcredential-returns-null-for-oauthtoken/28613143#28613143 That solved it for me. – pedrobolanos Feb 19 '15 at 17:43

0 Answers0