Pascal (Lazarus/Delphi)
Pascal (Lazarus/Delphi)
ebay: Add Digital Signature to HTTP Request
See more eBay Examples
Demonstrates how to add a digital signature to an ebay HTTP request.Chilkat Pascal (Lazarus/Delphi) Downloads
program ChilkatDemo;
// Demonstrates using the Chilkat Pascal wrapper via the C bridge DLL.
// Builds as a console application under Lazarus (FPC) or Delphi.
{$IFDEF FPC}
{$MODE DELPHI}
{$ENDIF}
{$APPTYPE CONSOLE}
uses
{$IFDEF UNIX}
cthreads,
{$ENDIF}
SysUtils,
CkDllLoader,
Chilkat.Http,
Chilkat.CkDateTime,
Chilkat.HttpResponse,
Chilkat.StringBuilder,
Chilkat.BinData,
Chilkat.PrivateKey,
Chilkat.EdDSA;
// ---------------------------------------------------------------------------
procedure RunDemo;
var
success: Boolean;
strPrivateKey: string;
strPublicKey: string;
strJwe: string;
sbBody: TStringBuilder;
sbSigBase: TStringBuilder;
sbSigInput: TStringBuilder;
dt: TCkDateTime;
unixTimeNow: string;
bdPrivKey: TBinData;
privKey: TPrivateKey;
bdToBeSigned: TBinData;
eddsa: TEdDSA;
sigBase64: string;
http: THttp;
sbContentDigestHdr: TStringBuilder;
sbSigHdr: TStringBuilder;
url: string;
jsonStr: string;
resp: THttpResponse;
begin
success := False;
// This example requires the Chilkat API to have been previously unlocked.
// See Global Unlock Sample for sample code.
// Note: Ebay provides a Key Management API
// See https://developer.ebay.com/api-docs/developer/key-management/overview.html
// The following test keys can be used:
//
// Ed25519
//
// Private Key:
//
// -----BEGIN PRIVATE KEY-----
// MC4CAQAwBQYDK2VwBCIEIJ+DYvh6SEqVTm50DFtMDoQikTmiCqirVv9mWG9qfSnF
// -----END PRIVATE KEY-----
strPrivateKey := 'MC4CAQAwBQYDK2VwBCIEIJ+DYvh6SEqVTm50DFtMDoQikTmiCqirVv9mWG9qfSnF';
// Public Key:
//
// -----BEGIN PUBLIC KEY-----
// MCowBQYDK2VwAyEAJrQLj5P/89iXES9+vFgrIy29clF9CC/oPPsw3c5D0bs=
// -----END PUBLIC KEY-----
strPublicKey := 'MCowBQYDK2VwAyEAJrQLj5P/89iXES9+vFgrIy29clF9CC/oPPsw3c5D0bs=';
// This example assumes you got a JWE for your given private key from the Ebay Key Management REST API.
// This JWE is just for example:
strJwe := 'eyJ6aXAiOiJERUYiLCJlbmMiOiJBMjU2R0NNIiwidGFnIjoiSXh2dVRMb0FLS0hlS0Zoa3BxQ05CUSIsImFsZyI6IkEyNTZHQ01LVyIsIml2IjoiaFd3YjNoczk2QzEyOTNucCJ9.2o02pR9SoTF4g_5qRXZm6tF4H52TarilIAKxoVUqjd8.3qaF0KJN-rFHHm_P.AMUAe9PPduew09mANIZ-O_68CCuv6EIx096rm9WyLZnYz5N1WFDQ3jP0RBkbaOtQZHImMSPXIHVaB96RWshLuJsUgCKmTAwkPVCZv3zhLxZVxMXtPUuJ-ppVmPIv0NzznWCOU5Kvb9Xux7ZtnlvLXgwOFEix-BaWNomUAazbsrUCbrp514GIea3butbyxXLNi6R9TJUNh8V2uan-optT1MMyS7eMQnVGL5rYBULk.9K5ucUqAu0DqkkhgubsHHw';
sbBody := TStringBuilder.Create;
sbBody.Append('{"hello": "world"}');
WriteLn('Body of request:');
WriteLn(sbBody.GetAsString());
// -------------------------------------------------
// Build the signature base string...
sbSigBase := TStringBuilder.Create;
sbSigBase.Append('"content-digest": sha-256=:');
sbSigBase.Append(sbBody.GetHash('sha256','base64','utf-8'));
sbSigBase.Append(':' + #10);
sbSigBase.Append('"x-ebay-signature-key": ');
sbSigBase.Append(strJwe);
sbSigBase.Append(#10);
sbSigBase.Append('"@method": POST' + #10);
// This is the path part of the URL without query params...
sbSigBase.Append('"@path": ');
sbSigBase.Append('/verifysignature');
sbSigBase.Append(#10);
// The is the domain, such as "api.ebay.com" w/ port if the port is something unusual.
// In this example, we're testing against a local docker test server (see the info at https://developer.ebay.com/develop/guides/digital-signatures-for-apis)
// Normally, I think it would just be "api.ebay.com" instead of "localhost:8080".
sbSigBase.Append('"@authority": ');
sbSigBase.Append('localhost:8080');
sbSigBase.Append(#10);
sbSigBase.Append('"@signature-params": ');
sbSigInput := TStringBuilder.Create;
sbSigInput.Append('("content-digest" "x-ebay-signature-key" "@method" "@path" "@authority")');
sbSigInput.Append(';created=');
dt := TCkDateTime.Create;
dt.SetFromCurrentSystemTime();
unixTimeNow := dt.GetAsUnixTimeStr(False);
sbSigInput.Append(unixTimeNow);
sbSigBase.AppendSb(sbSigInput);
// -------------------------------------------------
// Sign the signature base string using the Ed25519 private key
bdPrivKey := TBinData.Create;
bdPrivKey.AppendEncoded(strPrivateKey,'base64');
privKey := TPrivateKey.Create;
success := privKey.LoadAnyFormat(bdPrivKey,'');
if (success = False) then
begin
WriteLn(privKey.LastErrorText);
Exit;
end;
bdToBeSigned := TBinData.Create;
bdToBeSigned.AppendSb(sbSigBase,'utf-8');
eddsa := TEdDSA.Create;
sigBase64 := eddsa.SignBdENC(bdToBeSigned,'base64',privKey);
if (eddsa.LastMethodSuccess = False) then
begin
WriteLn(eddsa.LastErrorText);
Exit;
end;
WriteLn('sigBase64:');
WriteLn(sigBase64);
// ----------------------------------------------------------
// Send the JSON POST
http := THttp.Create;
http.SetRequestHeader('x-ebay-signature-key',strJwe);
sbContentDigestHdr := TStringBuilder.Create;
sbContentDigestHdr.Append('sha-256=:');
sbContentDigestHdr.Append(sbBody.GetHash('sha256','base64','utf-8'));
sbContentDigestHdr.Append(':');
http.SetRequestHeader('Content-Digest',sbContentDigestHdr.GetAsString());
sbSigHdr := TStringBuilder.Create;
sbSigHdr.Append('sig1=:');
sbSigHdr.Append(sigBase64);
sbSigHdr.Append(':');
http.SetRequestHeader('Signature',sbSigHdr.GetAsString());
sbSigInput.Prepend('sig1=');
http.SetRequestHeader('Signature-Input',sbSigInput.GetAsString());
// Add this header to make eBay actually check the signature.
http.SetRequestHeader('x-ebay-enforce-signature','true');
// Set the OAuth2 access token to add the "Authorization: Bearer <access_token>" to the header.
http.AuthToken := 'your_oauth2_access_token';
// The signature base string constructed above is valid if we send this POST to "http://localhost:8080/verifysignature"
// Normally, you'll send your POST to some api.ebay.com endpoint.
url := 'http://localhost:8080/verifysignature';
jsonStr := sbBody.GetAsString();
resp := THttpResponse.Create;
success := http.HttpStr('POST','http://localhost:8080/verifysignature',jsonStr,'utf-8','application/json',resp);
if (success = False) then
begin
WriteLn(http.LastErrorText);
Exit;
end;
WriteLn('Response status code: ' + resp.StatusCode);
WriteLn('Response body:');
WriteLn(resp.BodyStr);
sbBody.Free;
sbSigBase.Free;
sbSigInput.Free;
dt.Free;
bdPrivKey.Free;
privKey.Free;
bdToBeSigned.Free;
eddsa.Free;
http.Free;
sbContentDigestHdr.Free;
sbSigHdr.Free;
resp.Free;
end;
// ---------------------------------------------------------------------------
begin
try
RunDemo;
except
on E: Exception do
WriteLn('Unhandled exception: ', E.ClassName, ': ', E.Message);
end;
WriteLn;
{$IFDEF MSWINDOWS}
WriteLn('Press Enter to exit...');
ReadLn;
{$ENDIF}
end.