renewing ACAccount credentials on iOS

An iOS 5/6 device can have system-level Twitter/Facebook accounts that become disassociated from the underlying service accounts. This means that the ACAccountStore framework will return you ACAccount objects that can be used to sign requests and get access tokens, but NONE OF THE REQUESTS WILL WORK and you’ll get MYSTERIOUS OAUTH ERRORS and LOTS OF SUPPORT MAIL and be GRUMPY because it WORKS FOR YOU JUST FINE.

I’m not certain how to fake this state. Changing your Facebook password and choosing to log out other devices is pretty reliable, albeit really annoying if you actually use Facebook for anything. Likewise, changing your Twitter password might work. I think restoring the phone from backup will also cause this problem, especially if it’s a iTunes-based non-encrypted backup, because the passwords aren’t saved, but the phone won’t prompt you at any point to enter them again.

When this happens to Twitter account objects, I see server responses to otherwise perfectly reasonably signed requests with the error Bad Authentication data and the error code 215. I used to get This method requires authentication when calling the old 1.0 API, because the 1.0 API interprets a bad signature as no signature (REALLY ANNOYING), but the 1.1 API is a lot stricter.

When this happens with Facebook, I see Error validating access token: The session has been invalidated because the user has changed the password and sometimes Error validating access token: Session does not match current stored session. This may be because the user changed the password since the time the session was created or Facebook has changed the session for security reasons.

The solution to this is the method on ACAccountStore:

- (void)renewCredentialsForAccount:(ACAccount*)account
                        completion:(ACAccountStoreCredentialRenewalHandler)completionHandler;

From the docs:

For Twitter and Sina Weibo accounts, this method will prompt the user to go to Settings to re-enter their password.

For Facebook accounts, if the access token has become invalid due to a regular expiration, this method will obtain a new one.

If the user has deauthorized your app, this renewal request will return ACAccountCredentialRenewResultRejected.

Calling this method on the ACAccount object you’re trying to deal with will make-or-break it. I find that the token either works afterwards, or doesn’t, but now it doesn’t work because the iOS device knows that it doesn’t have a valid token. You may still have to punt the user into the Settings app to fix it. For instance, in the case of Twitter I find that calling renewCredentialsForAccount will pop up a system dialog about the problem.

Facebook is more subtle – the ACAccount object can still be used to get an access token, but that token will fail on the server with The session has been invalidated because the user has changed the password still. However, punting them manually into Settings.app at this point will ask them for a Facebook password and things will work afterwards.

Alas, it’s asynchronous. You can work around that. Call it on the ACAccount instance before you try to do something serious with it, or do work in the callback.

I hope this helps -someone-, because it sure would have helped me 6 months ago.

European privacy battle looms for Facebook, Google

To conform with Switzerland’s strict privacy law, Facebook could be required to contact people whose information has been posted online and ask them whether they agree to its being stored there, he said.

So, tricky. Suppose this works. Then what? Facebook, let’s say, removes the tagging in photos for people who aren’t users of the service.

Which, frankly, is almost no-one.

Yay privacy.

In return, no other service can ever build up the inertia facebook did, because you can barely use it till you persuade all your friends to sign up to the new one.

Facebook and OpenID

She stumbled upon a solution whereby nearly 99.9% of all test subjects accepted the program, as long as they were given a choice, even if they were only aware of the choice at a near unconscious level. While this answer functioned, it was obviously fundamentally flawed, thus creating the otherwise contradictory systemic anomaly, that if left unchecked might threaten the system itself. Ergo, those that refused the program, while a minority, if unchecked, would constitute an escalating probability of disaster.

The Architect

Oh, sorry. I was going to write something about Facebook making noises about openness. I must have got distracted.

Facebook locks down the feed even more

Well, as of next month, Facebook developers can no longer put things in a feed unless it’s going in as a direct result of an action that the owner of that feed performed on a facebook page.

Now, this is clearly spun as trying to prevent ‘you’ve been given a beer’ / ‘you’ve been bitten by a zombie’, etc messages. Not letting apps belonging to another person put entries into my feed is a good thing. But the documentation page says

Note that you should not be using a session_key for a user who is not actively using your application when calling this method.

Now, I read this as, you now can’t use a background process to put entries into a user’s feed using a session_id. You can only put things into their feed if they’re looking at your app while you’re doing it. And this is irritating. It completely breaks all the apps I use that syndicate the outside world into my Facebook profile – Twitter, delicious, CPAN, Dopplr, etc.

It seems that this is an effort to stop users like me, who just want to use existing services, but centralize update notification for the friends I have that don’t want to obsessively subscribe to 20 RSS feeds. Naturally, facebook don’t like me, because I don’t see, and therefore click, their ads. Forcing me to visit the site to tell my friends anything ‘fixes’ this.

Maybe I’m paranoid. Maybe I’m mis-reading ‘actively’, and they’re ok with installed apps using session_ids of users who aren’t logged in and using that app at this precise moment. I hope so.