Skip to main content

Request Signing

Use JWS to add an additional layer of security to every request.

Request signing adds an additional layer of security to every request you send to Paxos, and can help protect your account should your Paxos API Client ID and Secret become compromised. Once request signing is enabled on your account, Paxos rejects all unsigned requests to authenticated endpoints.

Request signing must be activated by Paxos. Contact Support to get started.

Signed requests use your own private key, similar to mTLS or SSH public authentication, and then attach the signature to the request as the Paxos-Signature HTTP header, using the JSON Web Signature (JWS) format.

Set Up Signed Request

To get started, you will need to have the Client ID and Secret available for constructing the payload. Additionally, install the JOSE/JWS library in the language of your choice, for example PyJWT which includes support for crypto.

Never share your private keys with anyone, especially for Production deployments. Using an HSM, secrets manager, or key-management service may provide an additional layer of protection.

➊ Generate Key Pair

Generate the JWS signature with your private key using a combination of the base64url encoded header and payload, using either the EdDSA (ed25519) or the ES256 algorithm.

To use the EdDSA (ed25519) algorithm when generating key pairs, install OpenSSL 3 using the package manager of your choice. Older versions of OpenSSL do not support the EdDSA (ed25519) algorithm.

To generate a new ES256 private key using the terminal:

  1. Ensure OpenSSL 3 is installed:
    openssl version
  2. Create a new ES256 private key in the current working directory:
    openssl ecparam -name prime256v1 -genkey -noout -out my-private-ec.pem
  3. Generate the public key in the current working directory:
    openssl ec -in my-private-ec.pem -pubout > my-public-ec.pem

The process for EdDSA (ed25519) keys is similar:

  1. Ensure OpenSSL 3 is installed:
    openssl version
  2. openssl genpkey -algorithm ed25519 -outform PEM -out my-private-key.pem
  3. openssl pkey -in my-private-key.pem -pubout > my-public-key.pem

Never share your private keys with anyone, especially for Production deployments. Using an HSM, secrets manager, or key-management service may provide an additional layer of protection.

➋ Add Public Key to Your Paxos Account

Go to Admin > API in either Sandbox or Production and find the API Credentials that require request signing.

Request signing must be activated by Paxos. Contact Support to get started.

Scroll down and use Edit API Credentials to make changes. Switch Request Signing to open the edit dialogue and add your Public Key.

Once you Save Changes, contact Support to get started.

➌ Generate Signed Request

Use a JOSE/JWS library such as PyJWT to generate the signature.

Construct Header

The header must include the following:

Header ItemDescription
kidThe Key ID of the configured Public Key. Retrieve from Admin > API > API Cretentials.
algThe algorithm used to generate the Key. The value must be: EdDSA or ES256. Retrieve from Admin > API > API Cretentials.
paxos.com/timestampThe current timestamp in UNIX time format. Signatures remain valid for 30 minutes after the specified timestamp.
paxos.com/request-methodThe POST and PUT methods also require the JWS payload in the body bytes.
paxos.com/request-pathThe endpoint path, including query parameters.

Putting it together, your header should look similar to the following:

{
"kid" : "5498f424-78aa-414b-a515-13929e6951db",
"alg" : "ES256",
"paxos.com/timestamp" : "1645503272",
"paxos.com/request-method" : "POST",
"paxos.com/request-path" : "/v2/transfer/deposit-addresses"
}

When using a POST or PUT method, include the JWS payload in the body bytes:

{"profile_id":"42bb1a2e-a68e-44d7-b5f1-59ccc5c13e91","crypto_network":"ETHEREUM"}

Create Signature

Use a library such as PyJWT to generate the request signature. First, install the library and start a new session. For example:

pip3 install "pyjwt[crypto]" && python3

Then generate the JWT signature:

>>> import jwt
>>> payload = b'{"profile_id":"42bb1a2e-a68e-44d7-b5f1-59ccc5c13e91","crypto_network":"ETHEREUM"}'
>>> with open('./my-private-ec.pem', 'rb') as f: key = f.read()
...
>>> alg = "ES256" if key.find('BEGIN EC PRIVATE'.encode('ascii')) > 0 else "EdDSA"
>>> headers = {"kid": "5498f424-78aa-414b-a515-13929e6951db", "alg": alg,
"paxos.com/timestamp": "1645503272",
"paxos.com/request-method" : "POST",
"paxos.com/request-path": "/v2/transfer/deposit-addresses"}
>>> signature = jwt.api_jws.encode(payload=payload, key=key, headers=headers,algorithm=alg)
>>> print(signature)
eyJ0eXAiOiJKV1QiLCJhbGciOiJFUzI1NiIsImtpZCI6IjU0OThmNDI0LTc4YWEtNDE0Yi1hNTE1LTEzO
TI5ZTY5NTFkYiIsInBheG9zLmNvbS90aW1lc3RhbXAiOiIxNjQ1NTAzMjcyIiwicGF4b3MuY29tL3JlcX
Vlc3QtbWV0aG9kIjoiUE9TVCIsInBheG9zLmNvbS9yZXF1ZXN0LXBhdGgiOiIvdjIvdHJhbnNmZXIvZGV
wb3NpdC1hZGRyZXNzZXMifQ.eyJwcm9maWxlX2lkIjoiNDJiYjFhMmUtYTY4ZS00NGQ3LWI1ZjEtNTljY
2M1YzEzZTkxIiwiY3J5cHRvX25ldHdvcmsiOiJFVEhFUkVVTSJ9.7x8b_4j1dFMd1XWcmpGaf5OiyU0lo
2fbGlbe8epuiAJFpFziwxhhKHbc7-DaqKMV9MTTARX8VM3d2YSugPEAow
>>> exit()

➍ Send Signed Request

Use the generated signature to send a signed request to Paxos. First, authenticate with the APIs. For example:

curl https://oauth.sandbox.paxos.com/oauth2/token \
-F grant_type=client_credentials \
-F client_id={client_id} \
-F client_secret={secret} \
-F scope="transfer:write_deposit_address"

Then send the signed API request:

curl -X POST https://api.sandbox.paxos.com/v2/transfer/deposit-addresses 
-H "Authorization: Bearer {access_token}"
-H "Paxos-Signature: eyJ0eXAiOiJKV1QiLCJhbGciOiJFUzI1NiIsImtpZCI6IjU0OThmNDI0LTc4Y
WEtNDE0Yi1hNTE1LTEzOTI5ZTY5NTFkYiIsInBheG9zLmNvbS90aW1lc3RhbXAiOiIxNjQ1NTAzMjcyIiw
icGF4b3MuY29tL3JlcXVlc3QtbWV0aG9kIjoiUE9TVCIsInBheG9zLmNvbS9yZXF1ZXN0LXBhdGgiOiIvd
jIvdHJhbnNmZXIvZGVwb3NpdC1hZGRyZXNzZXMifQ.eyJwcm9maWxlX2lkIjoiNDJiYjFhMmUtYTY4ZS00
NGQ3LWI1ZjEtNTljY2M1YzEzZTkxIiwiY3J5cHRvX25ldHdvcmsiOiJFVEhFUkVVTSJ9.7x8b_4j1dFMd1
XWcmpGaf5OiyU0lo2fbGlbe8epuiAJFpFziwxhhKHbc7-DaqKMV9MTTARX8VM3d2YSugPEAow"
-d '{"profile_id":"42bb1a2e-a68e-44d7-b5f1-59ccc5c13e91","crypto_network":"ETHEREUM"}'

Manage Signed Requests

For Production environments, you may want to create multiple API Credentials with different permissions and authentication. For example, you may want to sign all order and identity requests but not requests for historical data. To do this, you can create multiple API Credentials and then enable request signing for only those users or applications dealing with sensitive information.

  • Use Multiple Request Signing Keys. It is also possible for you to simultaneously use multiple request signing keys with a single API Credential. Once you add an additional request signing key, it is immediately available for use, along with any existing key, for the API Credential. Used in this way, you can assign different request signing keys to different users or applications that use the same API Credential. This can come in handy if you need to revoke access for an application or user with a specific key: The API Credentials remain active, along with the other keys.
  • Rotate API Credentials. If your API Credentials needs to be changed, the Rotate Credentials option regenerates a new Secret, leaving the Client ID unchanged. When you rotate credentials, you will need to update any implementation that uses the Client ID. Once that is done, your request signing keys work with the new Secret.