Net::OAuth help - "Could not authenticate with OAuth"


#1

Hello all,

I am using Perl’s Net::OAuth module. Here is the part of my code that is failing. Please assume that $message, $consumer_key, $consumer_secret, $url, $token and $token_secret are defined correctly, because I’ve checked them a million times. Also, my clock is set correctly.

my $ua = LWP::UserAgent->new; my $request = Net::OAuth->request("protected resource")->new( consumer_key => $consumer_key, consumer_secret => $consumer_secret, request_url => $url, request_method => 'POST', signature_method => 'HMAC-SHA1', timestamp => time, nonce => int(rand(2 ** 32)), token => $token, token_secret => $token_secret, extra_params => {status => $message}, ) $request->sign; my $response = $ua->post($request->to_url);

Pretty simple, yes? But every time, I get “401 Unauthorised - Could not authenticate with OAuth”. Here is what the POST request looks like:

/1/statuses/update.json?oauth_consumer_key=P5xo2gguKuZPlgFKJIwDWg&oauth_nonce=3058633389&oauth_signature=V3y%2F0xWFoXhWVxdQo44TJ%2Bg4k1A%3D&oauth_signature_method=HMAC-SHA1&oauth_timestamp=1328448285&oauth_token=15043295-NnGYKkq7fGxdEAraIba2zL6kPunXecwei47MYuY8&oauth_version=1.0&status=foo

I don’t think it’s an encoding issue because, really, how many ways are there to encode “foo”?

FWIW, this problem is not unique to Twitter. I get the same error posting to StatusNet (using its Twitter-compatible API), except with a slightly more useful error message “Invalid signature”. I was able to get around it by disabling the signature verification on my locally-installed StatusNet, but obviously I can’t do that with Twitter!

I’ve spent a couple of days bashing my head against the wall. Does anyone have any brilliant ideas, other than not using Net::OAuth (since this is a very widely-used module, and ought to be able to work)?

Thanks!


#2

Were you able to use this same library to negotiate your access token? if not, where did you get the access token and are you sure it’s still valid? Can you use it to make a request to account/verify_credentials?

Can you switch the OAuth module you’re using to use HTTP header-based auth instead of query-string based auth? It separates concerns dramatically.


#3

Yes I was, and yes I can account/verify_credentials successfully, which only involves changing a few lines in the code that is failing. That being so, will switching to header-based auth still help? I tried to do that before and it made no difference, but I wasn’t 100% certain that I was doing it right as I didn’t have a code sample to work from for header-based auth for a status update using Perl. Still, if it might make a difference, I’ll try again.


#4

It can make a difference because it minifies the opportunity for encoding errors in overly-helpful HTTP libraries as well as preventing mistakes like sending the data both in a POST body as well as on the query string. The separation of concerns makes debugging entirely more pleasant as well – ensures that the only data you’re passing in a URL or in the POST body are parameters related to the resource in question – in the case of statuses/update, you’d be only POSTing the status parameter. It looks like in this request you’re keeping the status field on the query string as well?


#5

Not at all sure if this was the best way to do it, because surprisingly I couldn’t find any Perl code samples that used header authorisation, but this also fails with 401 Unauthorized:

my $ua = LWP::UserAgent->new; my $url = "https://api.twitter.com/1/statuses/update.json"; my $request = Net::OAuth->request("protected resource")->new( consumer_key => $consumer_key, consumer_secret => $consumer_secret, request_url => $url, request_method => 'GET', signature_method => 'HMAC-SHA1', timestamp => time, nonce => int(rand(2 ** 32)), token => $token, token_secret => $secret, extra_params => {status => $message}, ); $request->sign; my $req = HTTP::Request->new(GET => $url . '?status=' . $message); $req->header('Content-type' => 'application/json'); $req->header('Authorization' => $request->to_authorization_header); my $response = $ua->simple_request($req);

#6

Oops sorry, account/verify_credentials is now failing too (maybe I misread it before?) so let me try again from scratch and post back once at least that is working.


#7

Things are going backwards! I can’t even get a request token now: I’m seeing “Failed to validate oauth signature and token”. That was definitely working before. So was account/verify_credentials, as I remember seeing that function return my name and other details. Could my application have been blacklisted?


#8

I’m still going with this and would be grateful for any more tips… this is what my base string looks like URL-encoded:

POST&https%3A%2F%2Fapi.twitter.com%2Fstatuses%2Fupdate.json&oauth_consumer_key%3D0jid3yku612HkohcuPw%26oauth_nonce%3D2151429472%26oauth_signature_method%3DHMAC-SHA1%26oauth_timestamp%3D1332076929%26oauth_token%3D15043295-yE5mWUZTJEqxoR1ziIuMTLnJnltcxhb9ihUMmx9w5%26oauth_version%3D1.0%26status%3DTesting

and URL-decoded:

https://api.twitter.com/statuses/update.json&oauth_consumer_key=0jid3yku612HkohcuPw&oauth_nonce=2151429472&oauth_signature_method=HMAC-SHA1&oauth_timestamp=1332076929&oauth_token=15043295-yE5mWUZTJEqxoR1ziIuMTLnJnltcxhb9ihUMmx9w5&oauth_version=1.0&status=Testing

Whether I do a status update or a verify_credentials, I get a signature failure. My code is now using header-based auth:

my $request = Net::OAuth->request("protected resource")->new( consumer_key => $consumer_key, consumer_secret => $consumer_secret, request_url => $url, request_method => 'POST', signature_method => 'HMAC-SHA1', timestamp => time, nonce => int(rand(2 ** 32)), token => $token, token_secret => $token_secret, extra_params => {status => utf8::decode($message)}, ); $request->sign; my $response = $ua->post($request->request_url, Authorization => $request->to_authorization_header, Content => [ status => $message ] );

#9

Sorry, I sorted it out. I had done a “chop” rather than a “chomp” after reading the tokens file, and chopped off the end of it. One character typo. Stupid mistake.


#10

Glad you got it worked out!


#11

Ive had to make a new twitter account because i had people impersonate me. I asked to be verified last time and was refused and therefore lost all my twitter account due to a hacking. If you could Please verify me this time that would be greatly appreiciated, Much love.