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 timestampand nonce will expire after 30 minutes. If your timestamp or nonce 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"
});