Delphi implementation of Application-only authentication


#1

Good day,

I try to implement the Api with Delphi. However, there is no Library available. So far I have following :

Function EncodeBase64(Input: String): String;
Var
fstream, fStringStream: TStringStream;
Begin
fstream := TStringStream.Create(Input);
fStringStream := TStringStream.create(’’);
EncodeStream(fstream, fStringStream);
Result := fStringStream.DataString;
End;

procedure TForm1.Button1Click(Sender: TObject);
Var
Credentials: String;
BearerToken: String;
MyHTTP: TIdHTTP;
Result: TMemoryStream;
UserPath: String;
begin
Credentials := ConsumerKey + ‘:’ + ConsumerSecret;
BearerToken := EncodeBase64(Credentials);
MyHTTP := TIdHTTP.Create(nil);
With MyHttp do
Begin
Request.UserAgent := ‘My Twitter App v1.0.23’;
Request.CustomHeaders.Add('Authorization: Basic '+BearerToken);
Request.ContentType := ‘application/x-www-form-urlencoded;charset=UTF-8’;
Request.CustomHeaders.Add(‘grant_type=client_credentials’);

IOHandler := TIdSSLIOHandlerSocketOpenSSL.Create(nil);

Result := TMemoryStream.Create;
Post('http://api.twitter.com/oauth2/token', Result);
Memo1.Lines.LoadFromStream(Result);
FreeAndNil(Result);

End;
MyHttp.Free;
end;

I always receive an Error 302 “Found”. If i activate redirection, I receive an Error “forbitten”.

What is wrong with the authentification ? Thank you for the help


#2

It looks like you’re trying to add grant_type=client_credentials as a HTTP header instead of a POST parameter.


#3

How do I set it as a post parameter ? I added it to the link as following :
https://api.twitter.com/oauth2/token?grant_type=client_credentials

but no change. Now, this is the complete code :

unit Unit1;

interface

uses
Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,
Dialogs, EncdDecd, IdHttp, StdCtrls, IdSSLOpenSSL, IdBaseComponent,
IdIntercept, IdLogBase, IdLogFile, IdComponent, IdTCPConnection, IdTCPClient,
IdLogEvent;

type
TForm1 = class(TForm)
Memo1: TMemo;
Button2: TButton;
Button3: TButton;
Button4: TButton;
IdLogEvent1: TIdLogEvent;
IdHTTP1: TIdHTTP;
procedure Button2Click(Sender: TObject);
procedure IdLogEvent1Received(ASender: TComponent; const AText,
AData: string);
procedure IdLogEvent1Sent(ASender: TComponent; const AText, AData: string);
private
{ Déclarations privées }
public
{ Déclarations publiques }
end;

var
Form1: TForm1;
Const
ConsumerKey: String = ‘XXXXX’; {Valid Credentials for a temporary Twitter Test Application}
ConsumerSecret: String = ‘XXXXXXXX’;
RessourcePost: String = ‘https://api.twitter.com/oauth2/token’; //?grant_type=client_credentials’;
RessourceHost: String = ‘api.twitter.com’;
ContentType: String = ‘application/x-www-form-urlencoded;charset=UTF-8’;

implementation

{$R *.dfm}

Function EncodeBase64(Input: String): String;
Var
fstream, fStringStream: TStringStream;
Begin
fstream := TStringStream.Create(Input);
fStringStream := TStringStream.create(’’);
EncodeStream(fstream, fStringStream);
Result := fStringStream.DataString;
End;

procedure TForm1.Button2Click(Sender: TObject);
Var
MyHttp: TIdHttp;
EncodedCredit: String;
Result: TStringStream;
Userpath: String;
begin
{Step 1: Encode consumer key and secret
https://dev.twitter.com/docs/auth/application-only-auth}
EncodedCredit := EncodeBase64(ConsumerKey + ‘:’ + ConsumerSecret);
{Step 2: Obtain a bearer token
https://dev.twitter.com/docs/auth/application-only-auth}
MyHttp := TIdHttp.Create(nil);
try
MyHttp.Request.ContentType := ContentType;
MyHttp.Request.ContentLength := 29;
MyHttp.Request.AcceptEncoding := ‘gzip’;
MyHttp.Request.Accept := ‘application/json’;
MyHttp.Request.Method := ‘Post’;
MyHttp.Request.BasicAuthentication := False;
MyHttp.Request.CustomHeaders.Add('Authorization: Basic '+EncodedCredit);
MyHttp.Request.CustomHeaders.Add(‘grant_type=client_credentials’);
MyHttp.Request.Host := RessourceHost;

{Temporary load the Library for OpenSSL}
Userpath := 'J:\';
LoadLibrary(PWideChar(Userpath+'libeay32.dll'));
LoadLibrary(PWideChar(Userpath+'ssleay32.dll'));
MyHttp.IOHandler := TIdSSLIOHandlerSocketOpenSSL.Create(nil);
MyHttp.Intercept := IdLogEvent1;
IdLogEvent1.Active := True;

Result := TStringStream.Create;
MyHttp.Post(RessourcePost, Result);
Memo1.Lines.LoadFromStream(Result);

finally
FreeAndNil(Result);
MyHttp.Free;
end;

end;

procedure TForm1.IdLogEvent1Received(ASender: TComponent; const AText,
AData: string);
begin
Memo1.Lines.Add('Received AText: '+Atext);
Memo1.Lines.Add('Received AData: '+AData);
end;

procedure TForm1.IdLogEvent1Sent(ASender: TComponent; const AText,
AData: string);
begin
Memo1.Lines.Add('Sent AText: '+Atext);
Memo1.Lines.Add('Sent AData: '+AData);
end;

end.

And this is the Indy Log File for the Sent parameters :

POST /oauth2/token HTTP/1.0Content-Type: application/x-www-form-urlencoded; charset=UTF-8Content-Length: 0Authorization: Basic XXXXeFpDcTRPNHM=grant_type=client_credentialsHost: api.twitter.com:443Accept: application/jsonAccept-Encoding: gzip, identityUser-Agent: Mozilla/3.0 (compatible; Indy Library)


#4

I don’t know your programming language well enough to tell you how to POST in it unfortunately.

Instead of MyHttp.Request.CustomHeaders.Add(‘grant_type=client_credentials’); you need to find where the MyHttp.Request object allows you to set a POST body – maybe it’s by a key/value pair, maybe it’s by you specifying the POST body as a string.