Twitter - Could not authenticate with OAuth (401) Error

妖精的绣舞 提交于 2019-12-24 00:47:19

问题


So, I'm doing a simple twitter app in Delphi and because I can't find a library already that works I decided to create my own. With the authenticate process I follow everything and get the Access token and secret token just fine.

When I try to use them (in the following code) I get the error {"error":"Could not authenticate with OAuth."}

This is true for both read and write requests (verify and posting). Any help would be greatly appreciated as I have been bashing my head against the wall over this.

Commands in the code below are the contents of the variables directly above the comments.

EDIT: Even just knowing what might cause "Could not authenticate with OAuth" instead of the more specific errors ("Invalid signature", "Missing parameters") would be of a giant help!

EDIT 2: Wireshark packet results.

HTTP/1.1 401 Unauthorized
Date: Tue, 06 Sep 2011 20:11:13 GMT
Server: hi
Status: 401 Unauthorized
WWW-Authenticate: OAuth realm="http://api.twitter.com"
X-Runtime: 0.01306
Content-Type: application/json; charset=utf-8
Content-Length: 114
Cache-Control: no-cache, max-age=300
Set-Cookie: _twitter_sess=xxxxxxxxxxx; domain=.twitter.com; path=/; HttpOnly
Expires: Tue, 06 Sep 2011 20:16:13 GMT
Vary: Accept-Encoding
Connection: close
{"error":"Could not authenticate with OAuth.","request":"\/1\/statuses\/update.json?status=This%20is%20a%20test."}

Code:

function TTwitter.SendRequest(Method: String; URI: String; Params: Array of String): ISuperObject;
const
  AuthHeaderFormat = 'OAuth oauth_nonce="%s", oauth_signature_method="%s", oauth_timestamp="%s", oauth_consumer_key="%s", oauth_token="%s", oauth_signature="%s", oauth_version="%s"';
var
  oauth_nonce,
  oauth_timestamp,
  SignKey,
  BaseString,
  Signature,
  AuthHeader,
  ResponseStr : String;
  BaseStringParams : Array of String;
  JSON : ISuperObject;
  I, J : Integer;
  EmptyParams : TStringList;
begin
  oauth_nonce := GenerateNonce;
  oauth_timestamp := GenerateTimeStamp;
  SignKey := fConsumerSecret + '&' + fAccessToken;
  J := 0;
  SetLength(BaseStringParams, Length(Params) + 6);
  For I := Low(Params) To High(Params) Do
    begin
    BaseStringParams[J] := Params[I];
    Inc(J);
  end;
  BaseStringParams[J] := 'oauth_consumer_key=' + fConsumerKey;
  BaseStringParams[J + 1] := 'oauth_nonce=' + oauth_nonce;
  BaseStringParams[J + 2] := 'oauth_signature_method=' + oauth_signature_method;
  BaseStringParams[J + 3] := 'oauth_token=' + fOAuthToken;
  BaseStringParams[J + 4] := 'oauth_timestamp=' + oauth_timestamp;
  BaseStringParams[J + 5] :=  'oauth_version=' + oauth_version;
  BaseString := CreateBaseString('POST', URI, BaseStringParams);
  //POST&http%3A%2F%2Fapi.twitter.com%2F1%2Fstatuses%2Fupdate.json&oauth_consumer_key%3DXXXXXXXXXXXXXXXX%26oauth_nonce%3D0F95A680F2231F689C702FCECAD1D449%26oauth_signature_method%3DHMAC-SHA1%26oauth_timestamp%3D1314988258%26oauth_token%3DXXXXXX-XXXXXXXXXXXXXXXX%26oauth_version%3D1.0%26status%3DThis%2520is%2520a%2520test.
  AuthHeader := Format(AuthHeaderFormat, [oauth_nonce,
                                          oauth_signature_method,
                                          oauth_timestamp,
                                          fConsumerkey,
                                          fOAuthToken,
                                          Signature,
                                          oauth_version]);
  //OAuth oauth_nonce="0F95A680F2231F689C702FCECAD1D449", oauth_signature_method="HMAC-SHA1", oauth_timestamp="1314988258", oauth_consumer_key="XXXXXXXXXXXXXXXXXX", oauth_token="XXXXXX-XXXXXXXXXXXXXXXX", oauth_signature="XXXXXXXXXXXXXXXXXXXXX", oauth_version="1.0"
  fHTTP.Request.CustomHeaders.AddValue('Authorization', AuthHeader);
  EmptyParams := TStringList.Create;
  Try
    If Length(Params) > 0 Then
      begin
      URI := URI + '?';
      For I := Low(Params) To High(Params) Do
        begin
        URI := URI + Params[I] + '&';
      end;
      URI := Copy(URI, 1, Length(URI) - 1);
      //http://api.twitter.com/1/statuses/update.json?status=This%20is%20a%20test.
    end;
    If Method = 'POST' Then
      begin
      ResponseStr := fHTTP.Post(URI, EmptyParams);
    end
    Else If Method = 'GET' Then
      begin
      ResponseStr := fHTTP.Get(URI);
    end;
    JSON := SO(ResponseStr);
    Result := JSON;
  Except
    On E:EIdHTTPProtocolException Do
      begin
      MessageBox(0, PChar(E.ErrorMessage), '', 0);
      //{"error":"Could not authenticate with OAuth.","request":"\/1\/statuses\/update.json?status=This%20is%20a%20test."}
    end;
  end;
  EmptyParams.Free;
end;

回答1:


So I found out that on this line:

fHTTP.Request.CustomHeaders.AddValue('Authorization', AuthHeader);

The way the component handles custom headers is that the delimiter for text is a comma. This means the program was adding a \r\n (new line) after every parameter I included for OAuth. No wonder it failed! Twitter wasn't even receiving the parameters!

Since I was checking the header before I added it to the headers I didn't even think that was the problem.

Thank you for your help! I probably wouldn't have delved into the code this deeply otherwise.




回答2:


I made a simple library/class to send status updates (post messages):

http://code.google.com/p/delphi-twitter-library/



来源:https://stackoverflow.com/questions/7323036/twitter-could-not-authenticate-with-oauth-401-error

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!