Set up and test request signing in your sandbox account.
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.
- 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.
Before You Begin
- Ensure you have an active individual (retail) sandbox account. Follow the steps in this guide.
- Have your sandbox API Client ID and Secret available to construct the payload.
- Install the JOSE/JWS library in the language of your choice. In this guide, we’ll use the PyJWT[crypto] library to generate the signature.
- If you need 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. In this guide, we’ll be using the more common ES256 algorithm.
Generate Key Pair
Generate keys using either the ES256 or EdDSA (ed25519) algorithm. ES256 is widely supported on most platforms, including Amazon and Google.
- See keygen and JWS in action on The Go Playground.
In the terminal, ensure the correct version of OpenSSL is installed:
$ openssl version
If you see command not found: openssl
in the output, ensure OpenSSL is properly installed and then try again in a new shell.
To generate a new ES256 private key in the current directory, enter the following in the terminal:
$ openssl ecparam -name prime256v1 -genkey -noout -out my-private-ec.pem
Next, generate the public key in the same directory:
$ openssl ec -in my-private-ec.pem -pubout > my-public-ec.pem
The output should be something similar to the following:
read EC key writing EC key
The process for EdDSA (ed25519) keys is similar:
$ openssl genpkey -algorithm ed25519 -outform PEM -out my-private-key.pem
If the command outputs Algorithm ed25519 not found
ensure you’ve installed OpenSSL 3 before generating your private key in a new shell.
$ openssl pkey -in my-private-key.pem -pubout > my-public-key.pem
- Properly store and protect your private key. Never share your private key with anyone.
Add Public Key to Your Paxos Account
- Sign in to your sandbox account and go to Settings > API Management.
- Select the API key for you want to enable signing for and ensure you assign appropriate scope. See this guide if you need to make changes to the API Key and scope.
- Scroll down to Danger Zone > Enable Request Signing, click on the lock icon to unlock the feature, then turn on request signing using the slider and "Update Credentials" to save the change!
- Then use Add Key to add your public key.
NOTE: If you get anInternal Server Error
message when adding a key, ensure Enable Request Signing is turned on (see the previous step) and try adding the key again. Once the key is added, you can then lock adding keys. - Click "Update Credentials".
-
Hold the pointer over the key and copy the ID. You’ll need both the Key ID (
kid
) and algorithm (alg
) when generating the signed request.
-
Ensure you turn on request signing before sending any signed requests.
Generate Signed Request
In this guide, we use the PyJWT[crypto] library to generate the signature. Whether you follow along with our Python3 library or use a different JOSE/JWS, the process is similar.
Construct Header
You will use the header information when generating the signed request.
- Keys are case sensitive.
The header must include the following information:
|
The Key ID of the configured Public Key. Retrieved from your Paxos sandbox account. |
|
The algorithm used to generate the Key. The value must be: Retrieved from your Paxos sandbox account. |
|
The current timestamp in UNIX time format. Signatures remain valid for 30 minutes after the specified timestamp. |
|
The API request method ( The |
|
The 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" }
Because this is a POST
method, we’ll include the JWS payload in the body bytes:
{"profile_id":"42bb1a2e-a68e-44d7-b5f1-59ccc5c13e91","crypto_network":"ETHEREUM"}
You’d do the same thing when using any PUT
method.
Generate Signature
Now that we’ve constructed our header, we’ll use the PyJWT[crypto] library to generate the request signature. First, install the library and start a new session:
$ pip3 install "pyjwt[crypto]" && python3
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 signature generated in the previous step to send a signed request to Paxos. First, authenticate with sandbox:
curl https://oauth.sandbox.paxos.com/oauth2/token \ -F grant_type=client_credentials \ -F client_id=$clientid \ -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 xRGvKetiw_phEDRnx4UgT7SrPJ9eQv-zjZthDGTYlXQ.Zx7o2uJd_Oit
rsddSqfb1CU92rq5lhnOFHo7YtrCvss" -H "Paxos-Signature: eyJ0eXAiOiJKV1QiLCJhbGciOiJFUzI1NiIsImtpZCI6IjU0OThmNDI0LTc4Y
WEtNDE0Yi1hNTE1LTEzOTI5ZTY5NTFkYiIsInBheG9zLmNvbS90aW1lc3RhbXAiOiIxNjQ1NTAzMjcyIiw
icGF4b3MuY29tL3JlcXVlc3QtbWV0aG9kIjoiUE9TVCIsInBheG9zLmNvbS9yZXF1ZXN0LXBhdGgiOiIvd
jIvdHJhbnNmZXIvZGVwb3NpdC1hZGRyZXNzZXMifQ.eyJwcm9maWxlX2lkIjoiNDJiYjFhMmUtYTY4ZS00
NGQ3LWI1ZjEtNTljY2M1YzEzZTkxIiwiY3J5cHRvX25ldHdvcmsiOiJFVEhFUkVVTSJ9.7x8b_4j1dFMd1
XWcmpGaf5OiyU0lo2fbGlbe8epuiAJFpFziwxhhKHbc7-DaqKMV9MTTARX8VM3d2YSugPEAow" -d '{"profile_id":"42bb1a2e-a68e-44d7-b5f1-59ccc5c13e91","crypto_network":"ETHEREUM"}'
Next Steps
- Learn more about managing signed requests.
- See keygen and JWS in action on The Go Playground.