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:
- 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.
 - 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?
 - 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?
 - 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];
            }
        }];
    }];
}