Skip to content

eBay/digital-signature-sdk-python

eBay Digital Signature SDK for Python

PyPI version Python versions License

HTTP message signatures provide a mechanism for end-to-end authenticity and integrity for components of an HTTP message.

This Python SDK is designed to simplify the process of generating digital signature headers and also provides a method to validate the digital signature headers.

Table of contents

Digital Signatures for Public API Calls

Due to regulatory requirements emanating from SCA for our European/UK sellers, we are requiring our developers to add a digital signature for every HTTP call that is made on behalf of a EU/UK seller to certain APIs.

This SDK is generic and the signature scheme is compliant with these finalized IETF standards:

Features

This SDK is intended to generate required message signature headers, as per the above IETF standards, and also provides a way to verify signature headers. There is also an example Python FastAPI service included with the SDK.

This SDK incorporates:

  • Generation of the following HTTP message signature headers:
    • Content-Digest: This header includes a SHA-256 or SHA-512 digest over the HTTP payload (as specified in RFC 9530 Digest Fields), if any. It is not required to be sent for APIs that do not include a request payload (e.g. GET requests).
    • Signature-Input: This header indicates which headers and pseudo-headers are included, as well as the order in which they are used when calculating the signature. It is created as specified in RFC 9421 HTTP Message Signatures.
    • Signature: The value of the Signature header is created as described in Section 3.1, Creating a Signature, of RFC 9421. It uses the Private Key value generated by the Key Management API.
    • x-ebay-signature-key: This header includes the JWE that is created using the Key Management API.
  • sign_message method to sign the incoming request object
  • validate_signed_message method to validate the signature of the incoming request object
  • There are individual methods as well to generate and validate the headers:
    • generate_content_digest
    • generate_signature
    • build_signature_input
    • build_signature_base
    • validate_content_digest
    • validate_signature

For more details on Digital Signatures for eBay APIs, please refer to the documentation.

Usage

Prerequisites

  • Python: 3.9 or higher
  • pip: Latest version recommended

Installation

pip install digital-signature-python-sdk

Quick Start

from digital_signature_sdk import sign_message, RequestToSign

# Load your private key
with open('path/to/privatekey.pem', 'rb') as f:
    private_key = f.read()

# Create a request to sign
request = RequestToSign(
    method="POST",
    path="/v1/sell/finances/transaction",
    authority="api.ebay.com",
    body=b'{"hello": "world"}',
    jwe="<JWE from Key Management API>"
)

# Generate signature headers
headers = sign_message(
    request,
    private_key,
    digest_algo="sha-256",
    algorithm="RSA"  # or "ED25519"
)

# Add headers to your HTTP request
print(headers)
# {
#     'Content-Digest': 'sha-256=:X48E9qOokqqrvdts8nOJRJN3OWDUoyWxBf7kbu9DBPE=:',
#     'x-ebay-signature-key': '<JWE>',
#     'Signature-Input': 'sig1=("content-digest" "x-ebay-signature-key" "@method" "@path" "@authority");created=1672531200',
#     'Signature': 'sig1=:MEUCIQDZm...aGFz:'
# }

Getting Started

Quick Setup & Run Example Server

The fastest way to get started with the SDK is to run the included example server:

# 1. Clone the repository
git clone https://github.com/eBay/digital-signature-python-sdk.git
cd digital-signature-python-sdk

# 2. Create virtual environment (optional but recommended)
python3 -m venv .venv
source .venv/bin/activate  # On Windows: .venv\Scripts\activate

# 3. Install dependencies
pip install -e ".[dev,examples]"

# 4. Generate development keys (required - no keys included for security)
python scripts/setup_dev_keys.py

# 5. Set up environment variables
cp .env.example .env
# Edit .env file and set your EBAY_JWE_TOKEN

# 6. Start the example server
python examples/server.py

The server will start at http://localhost:8080

Testing the Server

Once the server is running, test it with these curl commands:

Generate Signature Headers

curl -X POST http://localhost:8080/sign \
  -H "Content-Type: application/json" \
  -d '{"orderId": "12345", "amount": 99.99}' \
  -s | jq .

Example Response:

{
  "content-digest": "sha-256=:X48E9qOokqqrvdts8nOJRJN3OWDUoyWxBf7kbu9DBPE=:",
  "x-ebay-signature-key": "your-jwe-token",
  "signature-input": "sig1=(\"content-digest\" \"x-ebay-signature-key\" \"@method\" \"@path\" \"@authority\");created=1767602259",
  "signature": "sig1=:MEUCIQDZm...aGFz:"
}

Sign Complete Request

curl -X POST http://localhost:8080/sign-request \
  -H "Content-Type: application/json" \
  -d '{"message": "Hello eBay API"}' \
  -i

Validate Signatures

With jq (recommended):

# First generate a signature
RESPONSE=$(curl -s -X POST http://localhost:8080/sign \
  -H "Content-Type: application/json" \
  -d '{"test": "validation"}')

# Then validate it (requires jq)
echo $RESPONSE | jq -r '{
  "method": "POST",
  "path": "/ws/api.dll",
  "authority": "api.sandbox.ebay.com",
  "body": "{\"test\": \"validation\"}",
  "headers": .
}' | curl -X POST http://localhost:8080/validate \
  -H "Content-Type: application/json" \
  -d @- \
  -w "Status: %{http_code}\n"

Without jq (manual process):

# 1. Generate signature and copy the output
curl -X POST http://localhost:8080/sign \
  -H "Content-Type: application/json" \
  -d '{"test": "validation"}'

# 2. Use the signature components in validation (replace with actual values)
curl -X POST http://localhost:8080/validate \
  -H "Content-Type: application/json" \
  -d '{
    "method": "POST",
    "path": "/ws/api.dll",
    "authority": "api.sandbox.ebay.com",
    "body": "{\"test\": \"validation\"}",
    "headers": {
      "content-digest": "PASTE_CONTENT_DIGEST_HERE",
      "x-ebay-signature-key": "PASTE_JWE_TOKEN_HERE",
      "signature-input": "PASTE_SIGNATURE_INPUT_HERE",
      "signature": "PASTE_SIGNATURE_HERE"
    }
  }' \
  -w "Status: %{http_code}\n"

Success Response: HTTP 200 (empty body) Failure Response: HTTP 400 with error message

Available Endpoints

Endpoint Method Description
/sign POST Generate signature headers for request body
/sign-request POST Sign complete HTTP request using high-level API
/validate POST Validate signature using individual validation methods
/validate-request POST Validate signature using high-level validation API

Troubleshooting

"ModuleNotFoundError: No module named 'fastapi'"

pip install -e ".[dev,examples]"

"FileNotFoundError: Private and public keys must be provided"

python scripts/setup_dev_keys.py

"zsh: command not found: python"

# Activate virtual environment first
source .venv/bin/activate
# Or use python3
python3 examples/server.py

"zsh: command not found: jq"

# Install jq for JSON processing (optional)
brew install jq  # macOS
sudo apt-get install jq  # Ubuntu

Signature Validation

from digital_signature_sdk import validate_signed_message, RequestToSign

# Load public key
with open('path/to/publickey.pem', 'rb') as f:
    public_key = f.read()

# Recreate the request
request = RequestToSign(
    method="POST",
    path="/v1/sell/finances/transaction",
    authority="api.ebay.com",
    body=b'{"hello": "world"}'
)

# Validate
is_valid = validate_signed_message(
    request,
    headers,  # Headers dict with Signature, Signature-Input, Content-Digest
    public_key,
    algorithm="RSA"
)

print(f"Signature valid: {is_valid}")

Configuration

Environment Variables (Recommended for Security)

For production applications, use environment variables to keep secrets secure. Copy the .env.example file to .env and fill in your values:

cp .env.example .env

Edit the .env file with your actual values:

# Your JWE token from eBay's Key Management API
EBAY_JWE_TOKEN=your_actual_jwe_token_here

# Your key file paths
EBAY_PRIVATE_KEY_PATH=path/to/your/privatekey.pem
EBAY_PUBLIC_KEY_PATH=path/to/your/publickey.pem

# API endpoint configuration
EBAY_SIGNATURE_AUTHORITY=api.ebay.com
EBAY_SIGNATURE_PATH=/v1/sell/finances/transaction

The SDK automatically loads environment variables with the EBAY_ prefix and prioritizes them over configuration files.

Using Configuration with Environment Variables

from digital_signature_sdk import Config, sign_message, RequestToSign

# Load configuration that prioritizes environment variables
config = Config.load_secure_config("path/to/config.json")

# Load keys using the secure configuration
private_key = config.load_key_file(config.get("privateKey"))

# Get JWE token from environment (falls back to config file)
jwe_token = config.get("jwe")

# Create request
request = RequestToSign(
    method="POST",
    path=config.get("signatureComponents.path"),
    authority=config.get("signatureComponents.authority"),
    body=b'{"hello": "world"}',
    jwe=jwe_token
)

# Sign the request
headers = sign_message(request, private_key)

JSON Configuration Files (Legacy)

For backward compatibility, you can still use JSON configuration files. However, avoid storing secrets in these files for security reasons.

Example configuration for signing-only (example-config.json):

{
  "digestAlgorithm": "sha-256",
  "_jwe_comment": "JWE token should be provided via EBAY_JWE_TOKEN environment variable",
  "privateKey": "examples/keys/ed25519/privatekey.pem",
  "signatureComponents": {
    "method": "POST",
    "authority": "api.ebay.com",
    "path": "/v1/sell/finances/transaction"
  },
  "signatureParams": [
    "content-digest",
    "x-ebay-signature-key",
    "@method",
    "@path",
    "@authority"
  ]
}

For signing and validation (example-config-full.json):

{
  "digestAlgorithm": "sha-256",
  "algorithm": "Ed25519",
  "privateKey": "examples/keys/ed25519/privatekey.pem",
  "publicKey": "examples/keys/ed25519/publickey.pem",
  "jwtPayload": {
    "_pkey_comment": "Public key should be provided via EBAY_JWT_PAYLOAD_PKEY environment variable"
  },
  "signatureComponents": {
    "method": "POST",
    "authority": "api.ebay.com",
    "path": "/v1/sell/finances/transaction"
  },
  "signatureParams": [
    "content-digest",
    "x-ebay-signature-key",
    "@method",
    "@path",
    "@authority"
  ]
}

Environment Variable Reference

Environment Variable Description Example
EBAY_JWE_TOKEN JWE token from Key Management API <your-jwe-token>
EBAY_PRIVATE_KEY_PATH Path to private key file keys/ed25519/privatekey.pem
EBAY_PUBLIC_KEY_PATH Path to public key file keys/ed25519/publickey.pem
EBAY_SIGNATURE_ALGORITHM Signature algorithm Ed25519 or RSA
EBAY_DIGEST_ALGORITHM Digest algorithm sha-256 or sha-512
EBAY_SIGNATURE_AUTHORITY API hostname api.ebay.com
EBAY_SIGNATURE_PATH API path /v1/sell/finances/transaction
EBAY_SIGNATURE_PARAMS Signature parameters (comma-separated) content-digest,x-ebay-signature-key,@method

Running the Example

The SDK includes an example FastAPI server. To run it:

# 1. Generate development keys (first time only)
python scripts/setup_dev_keys.py

# 2. Set up environment variables
cp .env.example .env
# Edit .env with your actual EBAY_JWE_TOKEN

# 3. Install example dependencies
pip install fastapi uvicorn authlib

# 4. Run the example server
python -m examples.server

Key Generation

For security, no cryptographic keys are included in the repository. Generate your own:

# Quick setup - generates all development keys
python scripts/setup_dev_keys.py

# Advanced options
python -m digital_signature_sdk.key_generator --help

Note for Production Deployment

For Production, please host with HTTPS enabled.

Logging

Uses standard Python logging. Configure as needed in your application:

import logging
logging.basicConfig(level=logging.DEBUG)

License

Copyright 2025 eBay Inc. Developer: Qingyuan Liu

Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at

https://www.apache.org/licenses/LICENSE-2.0

Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License.

About

digital-signature-sdk-python

Resources

License

Code of conduct

Contributing

Security policy

Stars

Watchers

Forks

Releases

No releases published

Packages

No packages published