Lummox Labs

Mobile app maker since 2015

Login with Facebook. If you're lucky.

I'm working on a project where we've decided to support log in with Facebook. To start, I grabbed the docs from facebook's developer page. Registered a facebook app and matched the id with my app's bundle id. Put all the facebook plist nuggets in place in my app, fixed a transcription error (why no error messages, FB?) fixed a FB app setting error ("the app is not set up correctly". thanks.) and got login working after a couple hours.

At this point I should point out that despite a little pain, FB has made it remarkably easy. Just add a custom UIView as the login button and magically everything else works. Mostly.

The current problem is that the token isn't persisting between app launches, when it really should. So here's how I debugged it. This is for interest's sake; I'm writing this before I have the answer, so it's not a tutorial on how to fix bugs like a boss.

Step 1: Google. Nobody seems to be having this problem, so it's likely a config issue.

Step 2: Log everything I can about the token when FB gives it to me. Log the token on app start (nothing) and at login (something!). Verify that I can retrieve the token from the FB SDK after login is done. Check.

Step 3: Scour the FB documentation to find a step I missed, maybe a missed framework or something? Everything looks good, and I made sure the the Security framework was in the app, in order to use the secure keychain.

Step 4:  Download the FB SDK source (thanks, FB!). How is the token stored? The code was fairly easy to read, but there is lots going on, lots of little macros and helper function, and the keychain isn't easy to deal with to start. Looks like they store a UUID in NSUserDefaults, and the token in the keychain, associated with the UUID as a sanity check.

Step 5: Print out the contents of NSUserDefaults and Keychain at app launch. Time to get my hands dirty. NSUserDefaults has a UUID but no token, as expected. Keychain seems to have ... something but it takes a little finagling to print out whatever the data represents. The data in the keychain is NSData that's an NSArchive of an NSDictionary. I copy-pasted the code they use to unarchive it, and I've got a (surprisingly large) string of data called "tokenEncoded". I didn't bother to decode it because I've verified the most important thing: The token is there! 

So why the crap can't FB uncache and return it for me on a fresh launch? That's where I'm at now.

Update: More steps!

Step 6: Okay, so the token is in place in the keychain, maybe the Facebook SDK isn't trying to load it from cache? So check FBSDKTokenAccess to see where the cached token is actually set. Look for "g_currentAccessToken =". It's only set in +setCurrentAccessToken. So search for that. Among other places, it's called in FBSDKApplicationDelegate.application:didFinishLaunchingWithOptions:

Wait a tick. I'm definitely not calling that method. So these lines aren't being executed:

  FBSDKAccessToken *cachedToken = [[FBSDKSettings accessTokenCache] fetchAccessToken];
  [FBSDKAccessToken setCurrentAccessToken:cachedToken];

Which is a pretty good candidate for why the token isn't loading: Nobody asked to retrieve it from the keychain!

Lest you wonder, Facebook's guide doesn't mention that little part, though it is clear from the code comments that it's necessary:

/*!
 @abstract
 Call this method from the [UIApplicationDelegate application:didFinishLaunchingWithOptions:] method
 of the AppDelegate for your app. It should be invoked for the proper use of the Facebook SDK.

...

And sure enough, from my own didFinishLaunching, I call FBSDK didFinishLaunching, and everything is happy again. Another half-day wasted...