verify_credentials.json returning 401 consistently for certain accounts


I’m using GTMOAuth to authenticate my app to Twitter and everything seems fine when I tried it with some accounts I had.

Then I tried using my own and it failed. No X-Warning headers. Nothing. Just a 401.

Example of a good request:

2011-09-21 14:51:22.933 Stamped[37000:ec03] T Prepared GET URLRequest '<NSMutableURLRequest>'. HTTP Headers: {
    "Content-Length" = 0;
}. HTTP Body: .
2011-09-21 14:51:22.934 Stamped[37000:ec03] D Sending asynchronous GET request to URL
2011-09-21 14:51:22.934 Stamped[37000:ec03] T Prepared GET URLRequest '<NSMutableURLRequest>'. HTTP Headers: {
    Authorization = "OAuth oauth_consumer_key=\"kn1DLi7xqC6mb5PPwyXw\", oauth_token=\"374643948-TEEayCKuhJqCBk45p0NrNbXHKyfJBSesW7pDs8Kd\", oauth_signature_method=\"HMAC-SHA1\", oauth_version=\"1.0\", oauth_nonce=\"13816251454628867432\", oauth_timestamp=\"1316631082\", oauth_signature=\"2uHmHGM7ypUnZx9DEytFHPl7%2BLU%3D\"";
    "Content-Length" = 0;
}. HTTP Body: .
2011-09-21 14:51:23.180 Stamped[37000:ec03] D NSHTTPURLResponse Status Code: 200
2011-09-21 14:51:23.180 Stamped[37000:ec03] D Headers: {
    "Cache-Control" = "no-cache, no-store, must-revalidate, pre-check=0, post-check=0";
    Connection = close;
    "Content-Encoding" = gzip;
    "Content-Length" = 661;
    "Content-Type" = "application/json; charset=utf-8";
    Date = "Wed, 21 Sep 2011 18:51:23 GMT";
    Etag = "\"2f83a1d9c4f12aebcf5f2139aed1bc5c\"-gzip";
    Expires = "Tue, 31 Mar 1981 05:00:00 GMT";
    "Last-Modified" = "Wed, 21 Sep 2011 18:51:23 GMT";
    Pragma = "no-cache";
    Server = hi;
    "Set-Cookie" = "lang=en; path=/, _twitter_sess=BAh7DToMY3NyZl9pZCIlMGQxMTIwNGU0M2M4MzE0Y2QyNzcyYjFkNTRmOTNm%250AZTY6CXVzZXJpBOycVBY6DnJldHVybl90byIBj2h0dHBzOi8vYXBpLnR3aXR0%250AZXIuY29tL29hdXRoL2F1dGhvcml6ZT9vYXV0aF90b2tlbj1QaFNwQkRqbTFT%250AUkJxQTFLblBEYnN2YjFkaEZSWVV1NEduemF5ZGdvRFkmc2NvcGU9aHR0cCUz%250AQSUyRiUyRnd3dy5leGFtcGxlLmNvbSUyRm9hdXRoX3Njb3BlOhNwYXNzd29y%250AZF90b2tlbiItMWFmM2Y3NmM5OTQ0MzM5ZjVjNDM2ZGFkMmM1Nzg5Mjg5N2Jk%250AMWJiZjoHaWQiJWNiMDA3NzViNjQwNGU3OGQ0YTVmZjE4NWUyYzRjOWY4Igpm%250AbGFzaElDOidBY3Rpb25Db250cm9sbGVyOjpGbGFzaDo6Rmxhc2hIYXNoewAG%250AOgpAdXNlZHsAOgd1YTA6D2NyZWF0ZWRfYXRsKwgRzVONMgE%253D--0d3fe6f589c89ed3b8e21c68f5533c8ccb412210;; path=/; HttpOnly";
    Status = "200 OK";
    Vary = "Accept-Encoding";
    "X-Access-Level" = "read-write";
    "X-Content-Type-Options" = nosniff;
    "X-Frame-Options" = SAMEORIGIN;
    "X-Mid" = 5ebf2ab1fbae7ac566a8298d9d0ee7be173d08dd;
    "X-Ratelimit-Class" = "api_identified";
    "X-Ratelimit-Limit" = 350;
    "X-Ratelimit-Remaining" = 348;
    "X-Ratelimit-Reset" = 1316632828;
    "X-Revision" = DEV;
    "X-Runtime" = "0.03017";
    "X-Transaction" = "1316631083-95043-7162";
    "X-Transaction-Mask" = a6183ffa5f8ca943ff1b53b5644ef114ba972e98;
2011-09-21 14:51:23.181 Stamped[37000:ec03] T Read response body: 
2011-09-21 14:51:23.181 Stamped[37000:ec03] I Status Code: 200

and when I try with my own account (same exact code):

2011-09-21 14:46:34.440 Stamped[36939:ec03] T Prepared GET URLRequest '<NSMutableURLRequest>'. HTTP Headers: {
    "Content-Length" = 0;
}. HTTP Body: .
2011-09-21 14:46:34.440 Stamped[36939:ec03] D Sending asynchronous GET request to URL
2011-09-21 14:46:34.441 Stamped[36939:ec03] T Prepared GET URLRequest '<NSMutableURLRequest>'. HTTP Headers: {
    Authorization = "OAuth oauth_consumer_key=\"kn1DLi7xqC6mb5PPwyXw\", oauth_token=\"814122-fq3PHCjxz4yVep2hcgQYs42xmzxi6tlPlqSUsbc\", oauth_signature_method=\"HMAC-SHA1\", oauth_version=\"1.0\", oauth_nonce=\"13868093136204227369\", oauth_timestamp=\"1316630794\", oauth_signature=\"8o8CBnmjc3OzyOOXKIsGQCCKsGI%3D\"";
    "Content-Length" = 0;
}. HTTP Body: .
2011-09-21 14:46:34.750 Stamped[36939:ec03] D NSHTTPURLResponse Status Code: 401
2011-09-21 14:46:34.751 Stamped[36939:ec03] D Headers: {
    "Cache-Control" = "no-cache, max-age=300";
    Connection = "Keep-Alive";
    "Content-Encoding" = gzip;
    "Content-Length" = 109;
    "Content-Type" = "application/json; charset=utf-8";
    Date = "Wed, 21 Sep 2011 18:46:34 GMT";
    Expires = "Wed, 21 Sep 2011 18:51:34 GMT";
    "Keep-Alive" = "timeout=15, max=99";
    Server = hi;
    "Set-Cookie" = "_twitter_sess=BAh7DjoQc3RheV9zZWN1cmVUOgxjc3JmX2lkIiU5OWZjNmNkMWMzYTI1OTRj%250AYzk0NjU3NzVkYTFkZmEyNDoJdXNlcmkDKmwMOg5yZXR1cm5fdG8iAY5odHRw%250AczovL2FwaS50d2l0dGVyLmNvbS9vYXV0aC9hdXRob3JpemU%252Fb2F1dGhfdG9r%250AZW49bGhuT3BoMVVIcVVPSHZiY1B1R2RLSkdyZ1Jzc1VENUpKQlRvU3RaWk0m%250Ac2NvcGU9aHR0cCUzQSUyRiUyRnd3dy5leGFtcGxlLmNvbSUyRm9hdXRoX3Nj%250Ab3BlOhtzZXNzaW9uX3Bhc3N3b3JkX3Rva2VuIi0xZGNkMzE4ZDg3YTQxNDc2%250AYmU2ZTM2Nzg1N2MxNjU3NGM0MjU2N2NjOhNwYXNzd29yZF90b2tlbiItMWRj%250AZDMxOGQ4N2E0MTQ3NmJlNmUzNjc4NTdjMTY1NzRjNDI1NjdjYzoHaWQiJTFm%250AZGMzOTJlNWJhNjJiNGQzNjJjOTYyNWNiNTE3ZjNlIgpmbGFzaElDOidBY3Rp%250Ab25Db250cm9sbGVyOjpGbGFzaDo6Rmxhc2hIYXNoewAGOgpAdXNlZHsAOg9j%250AcmVhdGVkX2F0bCsIMW5PjTIB--8f06cc47f0d786b74dcf9e79e97297b0524568da;; path=/; secure; HttpOnly";
    Status = "401 Unauthorized";
    Vary = "Accept-Encoding";
    "Www-Authenticate" = "OAuth realm=\"\"";
    "X-Runtime" = "0.00635";
2011-09-21 14:46:34.752 Stamped[36939:ec03] T Read response body: 
2011-09-21 14:46:34.752 Stamped[36939:ec03] I Status Code: 401
2011-09-21 14:46:34.752 Stamped[36939:ec03] I Body: {"error":"Could not authenticate with OAuth.","request":"\/1\/account\/verify_credentials.json"}

It succeeds for some users but fails with others as more testing has proved. Any advice?


Hm, is there any chance you’d be able to provide raw HTTP dumps from the two requests? I don’t see anything obvious at this point…


Also, how are you obtaining the access token? Does the entire auth process succeed for all accounts?


Hi @kurrik,
The access token is obtained through GTMOauthTouch’s built-in functionality that brings you to the twitter login page then performs a callback on whether the process was successful. The token generation process is successful every single time (for all users). What’s odd is that if I were to quit the process, then go back in and generate a new token it works just fine (for my account at least).

I’d be much more suspicious of either GTMOAuth or my own code if the behavior weren’t so consistent. It consistently fails for my account and a specific few others, while succeeding on other test accounts just fine.

I’ll work on getting HTTP dumps for you, but what additional information would you be able to glean from them that you cannot above (just curious)?

Thanks for the response,


I was thinking there might be some sort of encoding issue with the signature or one of the parameters, but that’s honestly a shot in the dark. At this point I don’t really think that it’s an encoding thing, so don’t worry about the request dump if it is difficult to get.

It does sound like you’re somehow obtaining revoked access tokens. Normally I’d be suspicious of the “my access token” feature of your app’s settings page, but if every user (failing and non-failing) is reauthorizing and you’re keeping the newest of the granted tokens around, that’s a bit strange. It looks like GTMOauth stores tokens in the mac keychain - any chance there’s some old invalid tokens in there which are not being cleared upon reauthorization?

I did try building the example in /Examples/OAuthSample and managed to successfully authorize my test accounts - do you see the same problem if you use that sample?


Hey @kurrik,
Fixed the issue. I will follow up once I get this deadline under way. Thank you so much for your help on this. Say hi to @kmonkeyjam for me :slight_smile:



Good to hear! There’s at least a few folks interested in knowing what the issue was, so do please let us know when you get the chance :slight_smile:


Was the problem that GTMOauth uses the RestKit RKRequest? Did you get those warnings as well?


@tekje I did run into problems with the RKRequest on POST requests, but simply because you must make sure that all the headers that will ultimately be in the final request are present before you call. For example:

RKRequest* request = [self.auth requestWithResourcePath:kSomePath delegate:nil];
request.method = RKRequestMethodPOST;
[request.URLRequest setValue:@“application/x-www-form-urlencoded” forHTTPHeaderField:@“Content-Type”];
[request.URLRequest setHTTPMethod:@“POST”];
[request.URLRequest setHTTPBody:[body dataUsingEncoding:NSUTF8StringEncoding]];
[self.auth authorizeRequest:request.URLRequest];
[request send];

Otherwise RKRequest’s - (BOOL)prepareURLRequest method will set the necessary headers AFTER the auth token has been generated and there will be a mismatch.

Regarding getting the randomness to stop, it seems that the only changes I can point to would be adding a few lines that were in the example but not in my own project:

[auth setServiceProvider:@“Twitter”];


[authVC setBrowserCookiesURL:[NSURL URLWithString:@“”]];

I honestly don’t have any idea why this prevented the intermittent sign-in issues. OAuth is voodoo and a pain in the ass in my opinion (corroborated by both the author of GTMOAuth and some Twitter folk). I hope this helps people, but in all honesty, just copy the entire example from the GTMOAuth Samples/ directory and go from there.