Sample code for 30+ languages & platforms
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

Pascal (Lazarus/Delphi)
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.