Step-by-Step: Using Certificates for Enhanced iFrame Security
These instructions guide you through the process of generating the values you'll need in order to initialize secure tokenization on Spreedly iFrame.
Companion Reference Implementation
We also provide a Docker-based reference implementation that demonstrates all these steps in additional programming languages. It's available at our github repository
Step 0: Prerequisites
You'll need an environment key and access secret in order to make the following requests and store your certificate. These credentials are managed through the merchant portal.
Step 1: Generate a certificate
If you already have a non-expired certificate in PEM format (including its private and public key), skip to Step 2.
The private key will be used later to sign the Enhanced iFrame Security requests.
The following is an example on how to generate a certificate via the terminal. The commands are for macOS, so you may need to adjust syntax if you're on a different platform.
# Generate a private key
openssl genrsa -out private_key.pem 3072
# Generate a public key from the private key
openssl rsa -in private_key.pem -pubout -out public_key.pem
# Generate a self-signed certificate
# Change the subject to your own values (expiration, domain, etc)
openssl req -new -x509 -key private_key.pem -out cert.pem \
-subj "/C=US/ST=State/L=City/O=Organization/CN=payment.example.com"
Save the private key, public key, and certificate details securely.
Step 2: Upload certificate to Spreedly
Upload the certificate to Spreedly for verification of the signature in further steps. This is an example using curl
to generate the HTTP call and jq
to parse the certificate.
# Upload the certificate in Spreedly
curl --request POST \
--url https://core.spreedly.com/v1/certificates \
--user '<Environment-Key>:<Access-Secret>' \
--header 'accept: application/json' \
--header 'content-type: application/json' \
-d @- <<EOF
{
"certificate": {
"pem": $(jq -Rs . < cert.pem)
}
}
EOF
This request will respond with the certificate token (e.g., 6Q15M5VFJZ9QS9PEFTNP622W1T
).
Take note of the certificate token
for following steps.
{
"certificate": {
"token": "6Q15M5VFJZ9QS9PEFTNP622W1T",
"algorithm": null,
"cn": "test.com",
"o": "Organization",
"ou": null,
"c": "US",
"st": "State",
"l": "City",
"email_address": null,
"public_key": "-----BEGIN PUBLIC KEY-----\nMIIBojANBgkqhkiG9w0BAQEFAAOCAY8AMIIBigKCAYEApvEJ85dVdo9S5w1IjDOq\nSBlHdj75KxBbCsDEmxbtAFaOFT0PibNScsEwl0pj8vtJd+KkXzRIdd36sa2JtOSJ\nDvxWIqP6nfj4x4kY9apNYuqFBHEtJ+o90dWk5gQ/wh59pYNebVBowVW7I+onOii1\nS9QXwrPwNdTSr1lvDrKIFi0sMWnMvwnqn5Il/5n9Wz3GdyvfTdWy7I0R1mXY61Fz\ndmXhgn8HBp61IZTYGpHfOlmJc2VBhIaNWJz01OH5S5boi2cLYD7bOmTJtvEwVF3O\nZyIVOrPhs7hss37VtsdYKsHWE5WbCOQ4cuSTgpQWk9KlQJ0Rzo3Bzeo27bKMxVTN\n3b9QKHYbxAxPE5BB8CC/z0mSbjiR4c4zdYvdK5S2Zyu3ljInNLTa4DydsMLDx67F\nNXv5sco8JeqMQc65AGqGvN4pIXsyTcA+KKdBLbFKlzvRfD9XoLLpXNKQYtJthXc+\n7wc46ZbbJnBgpcq94W4Z4QSJBKcgkImCsGbt5z+FacXXAgMBAAE=\n-----END PUBLIC KEY-----\n",
"public_key_hash": "9O/yE2xL15f44q5ZKNj5M0JIVh9xGH4Lu2ne0JN+7mM=",
"csr": null,
"pem": "-----BEGIN CERTIFICATE-----\nMIIEjTCCAvWgAwIBAgIUIQrbscd4AJ8QaKGPxeogH5pd5dEwDQYJKoZIhvcNAQEL\nBQAwVjELMAkGA1UEBhMCVVMxDjAMBgNVBAgMBVN0YXRlMQ0wCwYDVQQHDARDaXR5\nMRUwEwYDVQQKDAxPcmdhbml6YXRpb24xETAPBgNVBAMMCHRlc3QuY29tMB4XDTI1\nMDQwNjAzMjMyN1oXDTI1MDQwNzAzMjMyN1owVjELMAkGA1UEBhMCVVMxDjAMBgNV\nBAgMBVN0YXRlMQ0wCwYDVQQHDARDaXR5MRUwEwYDVQQKDAxPcmdhbml6YXRpb24x\nETAPBgNVBAMMCHRlc3QuY29tMIIBojANBgkqhkiG9w0BAQEFAAOCAY8AMIIBigKC\nAYEApvEJ85dVdo9S5w1IjDOqSBlHdj75KxBbCsDEmxbtAFaOFT0PibNScsEwl0pj\n8vtJd+KkXzRIdd36sa2JtOSJDvxWIqP6nfj4x4kY9apNYuqFBHEtJ+o90dWk5gQ/\nwh59pYNebVBowVW7I+onOii1S9QXwrPwNdTSr1lvDrKIFi0sMWnMvwnqn5Il/5n9\nWz3GdyvfTdWy7I0R1mXY61FzdmXhgn8HBp61IZTYGpHfOlmJc2VBhIaNWJz01OH5\nS5boi2cLYD7bOmTJtvEwVF3OZyIVOrPhs7hss37VtsdYKsHWE5WbCOQ4cuSTgpQW\nk9KlQJ0Rzo3Bzeo27bKMxVTN3b9QKHYbxAxPE5BB8CC/z0mSbjiR4c4zdYvdK5S2\nZyu3ljInNLTa4DydsMLDx67FNXv5sco8JeqMQc65AGqGvN4pIXsyTcA+KKdBLbFK\nlzvRfD9XoLLpXNKQYtJthXc+7wc46ZbbJnBgpcq94W4Z4QSJBKcgkImCsGbt5z+F\nacXXAgMBAAGjUzBRMB0GA1UdDgQWBBQRHgCJZzf36qpt/nYuEQMaCPC8KTAfBgNV\nHSMEGDAWgBQRHgCJZzf36qpt/nYuEQMaCPC8KTAPBgNVHRMBAf8EBTADAQH/MA0G\nCSqGSIb3DQEBCwUAA4IBgQBbUW87HSyCCtEatl6GhORNkKQhXLcvzy4BBEi9r6HC\nVA8pD6cyJLqbMMiiQVOWB0tEyw3k0pNBDvjjXl57FZynjCzj4FQnE1bVgdfjV60J\njyJ5iVT+ooAvbaQgUfX+lSl6DNSes6bKMPoVBuri5NKFWIUSvSqjzlDAKDkF6VtC\n1Qz/OiUyOFoOYx93xayW1Ed5lNkor/eyO0wSdP9pk4N18r+wSuVXCbqxWVDmNVmm\ns+EbF+RCufPqqQ3eaUgEjOJxaOofbAQKjNumAVPsG3O8/TVE7gzirlDi5/MPFdFP\nKY24BXivZ1uyGZyWWgK8H3BeqvTwuoNMYOdQXITJllY3d0ErwIRdDh5GEpRIcMqX\nklrKT6yvphXjGVyXiHVuyOfe/UVerNPG/FOTqKlND4KC6IQUth26I1oyJ1mtfbor\nztguQo9eJpkCMTMAlMPbAWlNoYV5x1UpnPmBtmaA80No7mnPmlII2VODjt3/4iWb\nI22LT44+TQ/NhT5wCvYqOSI=\n-----END CERTIFICATE-----\n",
"created_at": "2025-04-06T03:23:27Z",
"updated_at": "2025-04-06T03:23:27Z"
}
}
Step 3: Generate parameters and signature
On your secure host, you need to generate the required parameters: nonce
andtimestamp
. Combined with your certificateToken
, these parameters will be signed with your private key. To learn more go to iFrame API lifecycle - Security Requirements.
Security Tip:
Generate a new, unique
nonce
value for each request and don't reuse old values. UUIDs work well for this purpose.
Important Note
Your
timestamp
andnonce
will expire after 30 minutes. If yourtimestamp
ornonce
expires before you send your iFrame request, you will need to start again from Step 3.Likewise, your certificate must be valid (not be expired) at the time of the iFrame request.
The following is an example on how to create your parameters. The commands are for macOS, so you may need to adjust syntax if using a different platform.
nonce=$(uuidgen)
timestamp=$(date +%s)
# from Step 2
certificateToken="6Q15M5VFJZ9QS9PEFTNP622W1T"
Generate a signature by using your private key from Step 1 to sign the data with SHA256
, then encode this signature as Base64
.
# Generate a signature
SIGNATURE=${nonce}${timestamp}${certificateToken}
echo -n $SIGNATURE | \
openssl dgst -sha256 -sign private_key.pem -binary \
| base64 -w 0
This command will output the server generated signature
, you will need this in Step 4:
# output of command, e.g.
CchzX5noiMcEpFlrz6ImWuzLXaUAvLLCpd6F3Y7gd7jAoY7SuJQVsJev3gp+gtQhZcuChVVfUze4mcOR2KjA5vqWtGXswHnd6xdg5l8m0HQNe5UL/2Zful06iltQfMbGT1QoflNTM62GFR5UBP4vtmgd4NmJUtt50vcveaGm8nnwgeUVz8Apsh/xwGwclkrjfT563+OJkfhgFwelk3Cj6QwHHm5sY7QuqX9eyBgVU0ApnJ2c/Om9J/TcYJ1mM+f33ULKQin6VQS/Zv/EmROtleuRLehWrXlPotOHfCiZsNpIU/H+IWNd7d6+0TiARiXlFeTwSTWTGgYBCdOdiZplJLSCvwcSlI1mRyZGIVz8+7U9zIbqaXoLh9SyQP9Jkhc4RqRw+n+9YNUTUbQYZt+WkYoKTXEYQai0OvixS7InKimPmCJ+aHpgbZmjGZhZeVAmINQMsodHHJ3DYaSx69UZf3Mq38Tze6GAiBMKCO3m9Yg/EE+YY2bkFqVmiYHJ8lacGVKfwjl
Step 4: Initialize Spreedly iFrame
Now you are ready to initialize your Spreedly iFrame. For detailed steps see iFrame API lifecycle initialization.
Insert values from previous steps:nonce
, timestamp
, certificateToken
, and signature
.
Spreedly.init("<Environment Key>", {
"numberEl": "spreedly-number",
"cvvEl": "spreedly-cvv",
"nonce": "dd6b70a5-e070-4fa2-a3ca-0db0b45f78d0",
"timestamp": "1738252535",
"certificateToken": "6Q15M5VFJZ9QS9PEFTNP622W1T",
"signature": "CchzX5noiMcEpFlrz6ImWuzLXaUAvLLCpd6F3Y7gd7jAoY7SuJQVsJev3gp+gtQhZcuChVVfUze4mcOR2KjA5vqWtGXswHnd6xdg5l8m0HQNe5UL/2Zful06iltQfMbGT1QoflNTM62GFR5UBP4vtmgd4NmJUtt50vcveaGm8nnwgeUVz8Apsh/xwGwclkrjfT563+OJkfhgFwelk3Cj6QwHHm5sY7QuqX9eyBgVU0ApnJ2c/Om9J/TcYJ1mM+f33ULKQin6VQS/Zv/EmROtleuRLehWrXlPotOHfCiZsNpIU/H+IWNd7d6+0TiARiXlFeTwSTWTGgYBCdOdiZplJLSCvwcSlI1mRyZGIVz8+7U9zIbqaXoLh9SyQP9Jkhc4RqRw+n+9YNUTUbQYZt+WkYoKTXEYQai0OvixS7InKimPmCJ+aHpgbZmjGZhZeVAmINQMsodHHJ3DYaSx69UZf3Mq38Tze6GAiBMKCO3m9Yg/EE+YY2bkFqVmiYHJ8lacGVKfwjl"
});
Updated 7 days ago