I try to connect me to my stripe payment test account with delphi.
The connect API is here:
Stripe connect API
Curl example:
curl https://api.stripe.com/v1/charges \
-u sk_test_CpkBxhx9gcmNYYQTZIXU43Bv:
I tried using Indy TIdHTTP component with TIdSSLIOHandlerSocketOpenSSL
and calling post with Tstringlist or TIdMultipartFormDataStream as parameter
but I receive always response: 401 - Unauthorized
Here my code:
var
Data: TIdMultipartFormDataStream;
https: TIdHTTP;
ssl: TIdSSLIOHandlerSocketOpenSSL;
begin
https := TIdHTTP.Create(self);
ssl := TIdSSLIOHandlerSocketOpenSSL.Create(Self);
https.IOHandler := ssl;
https.Request.BasicAuthentication := True;
Data := TIdMultipartFormDataStream.Create;
//Data.AddFormField('api_key', 'sk_test_CpkBxhx9gcmNYYQTZIXU43Bv');
Data.AddFormField('apikey', 'sk_test_CpkBxhx9gcmNYYQTZIXU43Bv');
https.Post('https://api.stripe.com/v1/charges', Data);
Memo1.lines.Add( https.ResponseText );
Data.Free;
end;
Any help or suggestion would bee very appreciated.
Thanks,
Peter
You must not use a form field to transfer the API key. Instead, set the Request.Username property. The password is empty, so Request.Passwort is unused. From the API docs on your linked page:
Authentication to the API occurs via HTTP Basic Auth. Provide your API
key as the basic auth username. You do not need to provide a password.
This example works with Indy 10.6.2 and OpenSSL libraries in the program folder:
program Project31229779;
{$APPTYPE CONSOLE}
uses
IdHTTP, SysUtils;
var
HTTP: TIdHTTP;
begin
HTTP := TIdHTTP.Create;
try
HTTP.Request.BasicAuthentication := True;
HTTP.Request.Username := 'sk_test_CpkBxhx9gcmNYYQTZIXU43Bv';
try
WriteLn(HTTP.Get('https://api.stripe.com/v1/charges'));
except
on E: EIdHTTPProtocolException do
begin
WriteLn(E.Message);
WriteLn(E.ErrorMessage);
end;
on E: Exception do
begin
WriteLn(E.Message);
end;
end;
finally
HTTP.Free;
end;
ReadLn;
end.
Note: you may also put the user name / password in the URL:
HTTP.Request.BasicAuthentication := True;
try
WriteLn(HTTP.Get('https://sk_test_CpkBxhx9gcmNYYQTZIXU43Bv:#api.stripe.com/v1/charges'));
Related
I tried a code I saw here but it didn't work for HTTPS. I need to download this page as a String, and add some Break lines on it to put the informations in order in a TMemo.
How to do it? I tried to use Indy but I failed because of the SSL.
I tried the solutions of this page: How to download a web page into a variable?
How to download this page https://api.rastrearpedidos.com.br/api/rastreio/v1?codigo=OP133496280BR thats just pure text and put in in a String? and also format it like that, in the lines of a TMemo:
"Objeto em trânsito - por favor aguarde"
"cidade":"SAO JOSE DOS CAMPOS"
"uf":"SP"
"dataHora":"18/06/2021 16:53"
"descricao":"Objeto postado","cidade":"SAO JOSE DOS CAMPOS","uf":"SP"
It's portuguese, English isn't my first language. Thanks if you guys could help me. I Use the Embarcadero Delphi 10.2 Tokyo.
When using Indy, assuming you are using Indy's default TIdSSLIOHandlerSocketOpenSSL component for SSL/TLS support, then make sure you put the 2 OpenSSL DLLs, ssleay32.dll and libeay32.dll, in the same folder as your EXE. You can get them from here:
https://github.com/IndySockets/OpenSSL-Binaries
Note that TIdSSLIOHandlerSocketOpenSSL only supports up to OpenSSL 1.0.2. If you need to use OpenSSL 1.1.x instead (for TLS 1.3+, etc), then use this SSLIOHandler instead. You will have to obtain the relevant OpenSSL DLLs from elsewhere, or compile them yourself.
Either way, once you decide which SSLIOHandler you want to use, the code is fairly simple:
var
HTTP: TIdHTTP;
SSL: TIdSSLIOHandlerSocketOpenSSL;
Response: string;
begin
HTTP := TIdHTTP.Create(nil);
try
// configure HTTP as needed (version, headers, etc)...
SSL := TIdSSLIOHandlerSocketOpenSSL.Create(HTTP);
// configure SSL as needed (TLS versions, certificates, etc)...
HTTP.IOHandler := SSL;
Response := HTTP.Get('https://api.rastrearpedidos.com.br/api/rastreio/v1?codigo=OP133496280BR');
finally
HTTP.Free;
end;
// use Response as needed...
end;
You also can use:
procedure TForm1.Button1Click(Sender: TObject);
var
i: Integer;
Request: TScHttpWebRequest;
Response: TScHttpWebResponse;
ResponseStr: String;
JSonValue: TJSonValue;
JsonArray: TJsonArray;
Name: String;
UserName: String;
Email: String;
begin
Request := TScHttpWebRequest.Create('https://jsonplaceholder.typicode.com/users');
try
Response := Request.GetResponse;
try
if Request.IsSecure then begin
ResponseStr := Response.ReadAsString;
JsonArray := TJSonObject.ParseJSONValue(ResponseStr) as TJsonArray;
try
for i:=0 to JsonArray.Count - 1 do begin
JsonValue := JsonArray.Items[i];
Name := JsonValue.GetValue('name');
UserName := JsonValue.GetValue('username');
Email := JsonValue.GetValue('email');
Memo1.Lines.Add('Name: ' + Name + ' - UserName: ' + UserName + ' - Email: ' + Email);
end;
finally
JsonArray.Free;
end;
end;
finally
Response.Free;
end;
finally
Request.Free;
end;
end;
I am struggling to get a response from Google Securetoken using Delphi 10.2.2 and Indy 10.
I've gotten my RefreshToken before from https://www.googleapis.com/identitytoolkit/v3/relyingparty/verifyPassword?key=XXX. This worked fine.
Now I try to refresh the token with https://securetoken.googleapis.com/v1/token, which doesn't work. I always get a 403 Forbidden error.
procedure TForm1.Button2Click(Sender: TObject);
var
l_Response: string;
l_PostData: TIdMultiPartFormDataStream;
l_IRESAccessToken: TIRESAccessToken;
begin
IdHTTP2.Request.ContentType := 'application/json';
IdHTTP2.Request.CharSet := 'utf-8';
l_PostData := TIdMultiPartFormDataStream.Create;
try
l_PostData.AddFormField('grant_type', 'refresh_token');
l_PostData.AddFormField('refresh_token', m_IRESAuth.RefreshToken);
l_PostData.AddFormField('key', 'XXX');
try
l_Response := IdHTTP2.Post('https://securetoken.googleapis.com/v1/token', l_PostData);
l_IRESAccessToken := TJson.JsonToObject<TIRESAccessToken>(l_Response);
except
on E: Exception do
ShowMessage('Error on request: '#13#10 + e.Message);
end;
finally
l_PostData.Free;
end;
end;
I tried an IOHandler that specifies TLS 1.2, and tried to send the post with a JSON object. Also, I set the hoKeepOrigProtocol flag in the TIdHTTP.HTTPOptions. Nothing worked so far, I always get 403 Forbidden.
I tried it with another program, no problems there.
Am I missing something?
Per Google's documentation:
Token Service REST API Reference:
HTTP request
POST https://securetoken.googleapis.com/v1/token
Request body
The request body contains data with the following structure:
URL-encoded representation
grant_type=string&code=string&refresh_token=string
The TStrings overload of TIdHTTP.Post() sends data in that format. That is the overload you need to use, not the TIdMultipartFormDataStream overload.
Also, as you can see above, this URL does not accept your key as input. It only accepts grant_type, code (which is ignored when grant_type is not 'authorization_code') and refresh_token.
Try this instead:
procedure TForm1.Button2Click(Sender: TObject);
var
l_Response: string;
l_PostData: TStringList;
l_IRESAccessToken: TIRESAccessToken;
begin
IdHTTP2.Request.ContentType := 'application/x-www-webform-urlencoded';
l_PostData := TStringList.Create;
try
l_PostData.Add('grant_type=refresh_token');
l_PostData.Add('refresh_token=' + m_IRESAuth.RefreshToken);
try
l_Response := IdHTTP2.Post('https://securetoken.googleapis.com/v1/token', l_PostData);
l_IRESAccessToken := TJson.JsonToObject<TIRESAccessToken>(l_Response);
except
on E: Exception do
ShowMessage('Error on request: '#13#10 + e.Message);
end;
finally
l_PostData.Free;
end;
end;
That being said, after reading the above documentation, I don't believe you can send an idToken from https://www.googleapis.com/identitytoolkit/v3/relyingparty/verifyPassword to https://securetoken.googleapis.com/v1/token as a refresh_token. I think you need to send it as an authorization_code instead, which then gives you a refresh_token. So try adding that extra step, if you have not already done so.
Sorry for the late response and thank you for the answer.
After consultation with the Main-API-Developer, he told me that they are using Firebase in the background. So the API request für Google is different.
https://cloud.google.com/identity-platform/docs/use-rest-api#section-sign-in-email-password
https://cloud.google.com/identity-platform/docs/use-rest-api#section-refresh-token
With this missing information the request works fine
procedure TForm1.Button2Click(Sender: TObject);
var
l_Response: string;
l_IRESAccessToken: TIRESAccessToken;
l_Json: string;
l_JsonToSend: TStringStream;
begin
l_Json := '{"grant_type": "refresh_token","refresh_token": "'+ m_IRESAuth.RefreshToken+ '"}';
l_JsonToSend := TStringStream.Create(l_Json, TEncoding.UTF8);
try
try
l_Response := IdHTTP2.Post('https://securetoken.googleapis.com/v1/token?key=XXX, l_JsonToSend);
l_IRESAccessToken := TJson.JsonToObject<TIRESAccessToken>(l_Response);
except
on E: Exception do
ShowMessage('Error on request: '#13#10 + e.Message);
end;
finally
l_JsonToSend.Free;
end;
end;
This question already has an answer here:
How can we connect with a website? Getting SSL error 1409442E
(1 answer)
Closed 2 years ago.
I'm using Delphi 10.3.3. The code below used to work but now I'm getting an error when trying to download a file over HTTPS:
Error connecting with SSL error:1409442E:SSL routines:SSL3_READ_BYTES:tlsv1 alert protocol version'
var
ms : tmemorystream;
ssl : TIdSSLIOHandlerSocketOpenSSL;
source,dest : string;
begin
source := 'https://www.myaddress.com/myfile.zip';
dest := 'c:\myfile.zip';
ms := TMemoryStream.Create;
try
if pos('https',source) > 0 then
begin
ssl := TIdSSLIOHandlerSocketOpenSSL.Create();
idh.IOHandler := ssl;
end;
idhttp1.get(source,ms);
ms.savetofile(dest);
result := 'ok';
finally
ms.Free;
end;
end;
TIdSSLIOHandlerSocketOpenSSL uses only TLS v1.0 by default and the server is rejecting that. You must explicitly allow newer TLS versions:
ssl := TIdSSLIOHandlerSocketOpenSSL.Create();
ssl.SSLOptions.SSLVersions := [sslvTLSv1, sslvTLSv1_1, sslvTLSv1_2];
idh.IOHandler := ssl;
Recent versions of Indy have https support built-in (so no need to create SSL IOHandler, Indy will take care of that automatically).
Also when dealing with files, it is better to use TFilestream instead of TMemoryStream because you you will get into trouble when trying to download files that don't fit into memory.
Here is a MRE for you:
program SO60578855;
{$APPTYPE CONSOLE}
{$R *.res}
uses
idHttp,
Classes,
System.SysUtils;
var
Http : TidHttp;
Fs : TFileStream;
begin
try
Fs := TFileStream.Create('c:\temp\100mb.bin', fmcreate);
Http := TidHttp.Create(nil);
try
Http.Get('https://speed.hetzner.de/100MB.bin', Fs);
finally
Http.Free;
Fs.Free;
end;
except
on E: Exception do
Writeln(E.ClassName, ': ', E.Message);
end;
Readln;
end.
I have to write a program (Delphi XE5, Indy 10: TIdHTTP & TIdSSLIOHandlerSocketOpenSSL) which can connect to a web service with client authentication. With several days of working, finally it has become success. I can connect using the authentication, setting the TIdSSLIOHandlerSocketOpenSSL’s SSLOptions.CertFile and SSLOptions.KeyFile properties. It’s fine. (I've got a pfx file from my partner, I exported it to a certificate and a private key file with OpenSSL so I use these 2 files in the program.)
I have one TButton, TMemo and TIdHTTP component on the form.
Source code (Button's click event - the IdHTTP1.Request.ContentType := '.......' line is necessary just for the communication because of the server settings):
procedure TForm1.Button1Click(Sender: TObject);
var
URL: string;
XML: TStrings;
S: string;
Req: TStream;
SL: TStringList;
SSL1 : TIdSSLIOHandlerSocketOpenSSL;
begin
XML := TStringList.Create;
XML.Add('<soap:Envelope xmlns:ns="http://docs.oasis-open.org/ws-sx/ws-trust/200512" ' +
'xmlns:soap="http://www.w3.org/2003/05/soap-envelope">');
…
XML.Add(' <soap:Body>');
…
XML.Add(' </soap:Body>');
XML.Add('</soap:Envelope>');
URL := 'https://…………………….';
end
Req := TStringStream.Create(XML.Text, TEncoding.UTF8);
try
SSL1 := TIdSSLIOHandlerSocketOpenSSL.Create(nil);
SSL1.SSLOptions.CertFile := 'd:\certificate.pem';
SSL1.SSLOptions.KeyFile := 'd:\private.pem';
SSL1.SSLOptions.Mode := sslmClient;
try
SSL1.SSLOptions.Method := sslvSSLv23;
IdHTTP1.IOHandler := SSL1;
IdHTTP1.Request.ContentType := 'application/soap+xml;charset=UTF-8;action="http://docs.oasis-open.org/ws-sx/ws-trust/200512/RST/Issue"';
S := IdHTTP1.Post(URL, Req);
finally
SSl1.Free;
end;
finally
Req.Free;
end;
ResultMemo.Lines.Add(Format('Response Code: %d', [IdHTTP1.ResponseCode]));
ResultMemo.Lines.Add(Format('Response Text: %s', [IdHTTP1.ResponseText]));
SL := TStringList.Create;
try
SL.Text := S;
ResultMemo.Lines.AddStrings(SL);
finally
SL.Free;
end;
end;
The problem is: my partner said this case is not the best if the file I use is not password-protected. They told me how to create a password-protected (and encrypted) file for the KeyFile with OpenSSL. When I set this password-protected file to the SSLOptions.KeyFile I get the following error message: „Could not load key, check password. error:0906A068:PEM routines:PEM_do_header:bad password read.”
I tried to set the password in the idHTTP1.Request.Password property, but the result is the same.
Question: how and where do I have to set the password for the KeyFile if I have to use a password-protected keyfile? Because I have to publish the certification files, too, the best solution would be to set the password in the program and use the password-protected KeyFile, instead of using not the password-protected KeyFile.
Thanks a lot.
Regards,
Attila
Use the IdSSLIOHandlerSocketOpenSSL.OnGetPassword event and set it here.
procedure TForm1.IdSSLIOHandlerSocketOpenSSL1GetPassword(var Password: string);
begin
Password := 'thepassword';
end;
I want to make the registration process a user name and password. I use Delphi 7. Component which can be done? (I know very little english, sorry.)
http request is easiest method (with GET, or POST), but preferred you'll want to use SSL if you dont want passwords/usernames passed along to your webserver un-encrypted.
Example of using POST request:
uses
IdHTTP;
function PostData(const URL: string; Params: TStrings): string;
var
IdHTTP: TIdHTTP;
begin
Result := '';
IdHTTP := TIDHttp.Create(nil);
try
IdHTTP.HandleRedirects := True;
IdHTTP.ReadTimeout := 5000;
Result := IdHTTP.Post(URL, Params);
finally
IdHTTP.Free;
end;
end;
Optionally you can write your own socket, but that will be more difficult because you'll have to write your own listener. (Which is usually not allowed on most shared hosting plans.)