Delphi/RAD Studio XE 5 OAuth1 Authentication issue with Twitter and Tumblr (Solution)
10/6/2013 5:11 PM
Embarcadero's new RAD Studio XE5 introduces unified, single source cross platform Development for Win32, Win64, Mac OS X, iOS and Android. This is currently the best way to write cross platform applications over all these platforms. Certainly Mono, can work to hit most of them; but deployment of such apps along with their performance is extremely complicated. RAD Studio provides native level code on all of these platforms. At some point, I hope to post more on this in detail.
In addition, they've implemented a new REST Client API supporting the REST Protocol and Open Authentication 1.0/1.1 and Open Authentication 2.0 this allows easy connection to most of the modern web API's.
Unfortunately there is a bug in the OAuth1 client that causes OAuth1 authentication to fail in the western hemisphere for Twitter, Tumblr and other 1.1 API's I've tried.
It appears that if your UTC offset is positive, Twitter works as intended (as does Tumblr) however if you are in a timezone west of Greenwich, you'll find yourself unauthorized by Twitter.
Twitter (and Tumblr) require the OAuth1 timestamp to be in GMT. Thus one must convert the current date time to UTC before converting it to a UNIX timestamp. This is an error in the supplied unit REST.Authenticator.Oath.pas.
To fix this problem, copy REST.Authenticator.Oath.pas from the /source/data/rest directory under your RS XE 5 program driectly to your local project directory.
Add it to your project and when you build, Delphi will take this version of the code rather than the default version.
Locate the function TOAuth1Authenticator.GenerateTimeStamp and alter it to convert the local time pulled from Now() to UTC.
class function TOAuth1Authenticator.GenerateTimeStamp: string; begin
result := IntToStr(DateTimeToUnix(TTimeZone.Local.ToUniversalTime(Now)));
I'm not sure why any positive offset works, e.g. UTC+6:30 but it does. So there are probably a couple layers to this, but this will make the REST Client with OAuth1 work properly with Twitter.
So I got all the way through on Tumblr to the point where I needed to request an Access_Token and Access_Token_Secret. This worked fine on Twitter. On Tumblr, things get a little more complicated. Instead of seeing a PIN number, the callback response has the the request_token in the oauth_token field and a character string in ouath_verifier that you have to capture and use (just the oauth_verifier...the oauth_token is the request_token) as the VerifierPIN.
Now, when you do that, however, you keep getting authentication failed 401.
Took me a while to figure out what the problem is but...once again it's in the REST.Authenticator.OAuth unit.
When you don't yet have an access_token or access_token_secret, the OAuth workflow says to use request_token and request_token_secret in their place.
The Embarcadero OAuth code does this for access_token, but it does NOT do this for access_token_secret.
Therefore in the unit, on line 460 where you are generating the OAuth signature, you have to adjust the code to check if access_token_secret is blank, and if so (and at this stage the answer is yes) and replace it with request_token_secret.
if AAuthenticator.AccessTokenSecret <>'' then
LSigningKey := AAuthenticator.ConsumerSecrect + '&' + AAuthenticator.AccessTokenSecret // do not localize
else //JLL added to comply with what I see elsewhere for Tumblr. And is consistent with using RequestToken for AccessToken before we have it.
LSigningKey := AAuthenticator.ConsumerSecrect + '&' + AAuthenticator.RequestTokenSecret ;
This will make this stage work with Tumblr.
For some reason it wasn't a problem with Twitter...who knows, it should have been in a logically consistent world....