Payload Encryption (Optional)

Payload encryption for the Evaluation API enables secure, tamper-proof communication between clients and Socure’s RiskOS™ using industry-standard JWE and JWS protocols.


How it works

This feature allows you to securely send sensitive identity data in a POST request to Socure's /api/evaluation endpoint. It ensures payload confidentiality and integrity through dual-layer encryption and digital signatures.

You can use this feature to:

  • Encrypt sensitive payloads sent to RiskOS™.
  • Ensure payload integrity through digital signature validation.
  • Meet compliance and security requirements using TLS and RSA standards.
📘

Key management and constraints:

  • Unique Keys Required: You cannot reuse encryption keys from Socure ID+. A unique X.509 certificate exchange must be completed specifically for your RiskOS™ account.
  • Shared Keys across Use Cases: RiskOS™ does not support different key pairs for different use cases within the same account. All teams using the same account must use the same configured key pair.
  • Optional Encryption: Encryption is triggered by the X-Payload-Encrypted: true header. If a specific team or use case does not require encryption, omit this header and send a standard JSON payload.

Before you start

Make sure that you:

Have access to the RiskOS™ platform.
Have completed the X.509 certificate exchange with Socure.
Possess a valid RiskOS™ API key for the appropriate environment.
Use TLS 1.2 or higher (TLS 1.3 recommended).

Choose your environment

Start with Sandbox for development and testing, then move to Production for live applications.

https://riskos.sandbox.socure.com/api/evaluation
  • No real customer data
  • Free testing environment
  • Unlimited API calls

Get an API key

  1. In the Sandbox RiskOS™ Dashboard, go to Developer Workbench > API Keys.
  2. Copy your API key securely.

Step 1 - Header and authentication

Endpoint

POST https://riskos.sandbox.socure.com/api/evaluation
POST https://riskos.socure.com/api/evaluation

Authentication and headers

  • Include your API key in the Authorization header as a Bearer token, along with standard JSON headers.
  • X-Payload-Encrypted: true is required to indicate that the payload is JWE-encrypted.
Authorization: Bearer YOUR_API_KEY
Content-Type: application/json
Accept: application/json
X-Payload-Encrypted: true

Step 2 - Payload encryption

This implementation is based on the JWE (JSON Web Encryption) and JWS (JSON Web Signature) standards.


Supported protocols

LayerAlgorithm
SigningRS256 (RSA + SHA256)
Key EncryptionRSA_OAEP_256
Content EncryptionA256GCM (AES-GCM 256-bit)

Encryption flow

From Customer to Socure (request encryption):

  1. Sign the payload using the customer's private RSA key with RS256.
  2. Generate a unique 256-bit AES key (CEK).
  3. Encrypt the signed payload using the CEK with A256GCM.
  4. Encrypt the CEK using Socure's public RSA key with RSA_OAEP_256.
  5. Package all components (header, encrypted CEK, encrypted payload) into a JWE string.
  6. Send the JWE string in the request body under the field:
{
  "encrypted_request": "<JWE_STRING>"
}
  1. Socure decrypts the CEK with its private key.
  2. Socure decrypts the payload using the CEK.
  3. Socure verifies the signature using the customer's public key.

From Socure to Customer (response encryption):

  1. Socure signs the response payload using its private RSA key with RS256.
  2. Generates a unique 256-bit AES key (CEK).
  3. Encrypts the signed payload with the CEK using A256GCM.
  4. Encrypts the CEK with the customer's public RSA key using RSA_OAEP_256.
  5. Packages the encrypted components into a JWE string and returns it in the API response:
{
  "eval_id": "<uuid>",
  "encrypted_response": "<JWE_STRING>"
}
  1. Customer decrypts the CEK using their private key.
  2. Customer decrypts the payload using the CEK.
  3. Customer verifies the signature using Socure's public key.

Step 3 - Request body

Only one parameter is required:

{
  "encrypted_request": "<JWE_String>"
}

Step 4 - API responses

Success — HTTP 200:

HTTP status code 200 indicates that the encrypted payload was successfully processed. The response includes an encrypted_response field containing the encrypted evaluation result:

{
  "eval_id": "123456-abcdef-123456",
  "encrypted_response": "<JWE_String>"
}

Error — HTTP 400:

HTTP status code 400 indicates that Socure was unable to interpret the encrypted payload—typically due to issues with encryption format or signature verification. The response includes an error field with details:

{
  "eval_id": "123456-abcdef-123456",
  "error": "Payload encryption is not supported for this api-key"
}
💡

Troubleshooting:

If you receive the error "Payload encryption is not supported for this api-key", verify that you are not using keys associated with a different Socure product (like ID+). Keys must be exchanged specifically for your RiskOS™ account.


Error — HTTP 500:

HTTP status code 500 means the payload was verified, but Socure failed to encrypt or sign the response due to an internal error. The response includes an error field with details:

{
  "eval_id": "123456-abcdef-123456",
  "error": "The encrypted payload is verified with success, however, server has internal problems to handle response encryption"
}

Encryption error messages

The error field may contain one of the following messages:

  • The payload encryption is not supported for this API key.
  • The payload format is not supported.
  • The encrypted payload is not in JWE (JSON Web Encryption) format.
  • The signed payload is not in JWS (JSON Web Signature) format.
  • The payload decryption failed.
  • The payload signature could not be verified.

Sample code

This Java-based example uses the Nimbus JOSE + JWT library to demonstrate signing and encryption.


Encrypt / Decrypt payload

import java.security.interfaces.*;
import javax.crypto.*;

import com.nimbusds.jose.*;
import com.nimbusds.jose.crypto.*;

public class Cipher {

   public String encrypt(String message, RSAPublicKey rsaPublicKey) throws Exception {

       // Assign the default JWE alg and enc.

       JWEAlgorithm alg = JWEAlgorithm.RSA_OAEP_256;
       EncryptionMethod enc = EncryptionMethod.A256GCM;

       // Generate the Content Encryption Key (CEK).

       KeyGenerator keyGenerator = KeyGenerator.getInstance("AES");
       keyGenerator.init(enc.cekBitLength());
       SecretKey cek = keyGenerator.generateKey();

       // Encrypt the JWE with the RSA public key + specified AES CEK.
       
       JWEObject jwe = new JWEObject(
               new JWEHeader(alg, enc),
               new Payload(message));
       jwe.encrypt(new RSAEncrypter(rsaPublicKey, cek));
       return jwe.serialize();
   }

   public String decrypt(String jweString, RSAPrivateKey rsaPrivateKey) throws Exception {

       // Decrypt the JWE with the RSA private key.

       JWEObject jwe = JWEObject.parse(jweString);
       jwe.decrypt(new RSADecrypter(rsaPrivateKey));

       return jwe.getPayload().toString();
   }
}

Sign / Verify signature

import com.nimbusds.jose.*;
import com.nimbusds.jose.crypto.RSASSASigner;
import com.nimbusds.jose.crypto.RSASSAVerifier;
import com.nimbusds.jose.jwk.RSAKey;

public class Signature {

   public String sign(String message, RSAKey rsaJWK) throws Exception {

       // Create RSA-signer with the private key

       JWSSigner signer = new RSASSASigner(rsaJWK);

       // Prepare JWS object with simple string as payload

       JWSObject jwsObject = new JWSObject(
               new JWSHeader.Builder(JWSAlgorithm.RS256).keyID(rsaJWK.getKeyID()).build(),
               new Payload(message));

       // Compute the RSA signature

       jwsObject.sign(signer);

       // Serialize to compact form.

       return jwsObject.serialize();
   }

   public boolean verify(String jwsToken, RSAKey rsaPublicKey) throws Exception {

       // To parse the JWS and verify it.

       JWSObject jwsObject = JWSObject.parse(jwsToken);
       JWSVerifier verifier = new RSASSAVerifier(rsaPublicKey);

       return jwsObject.verify(verifier);
   }

}

Message sender

import com.nimbusds.jose.jwk.RSAKey;

//This class is to simulate customer's actions below:
// 1. Use customer-generated RSA2048 private key to sign;
// 2. Use the Socure-generated RSA2048 public key to wrap AES key.

public class Sender {
   RSAKey rsaKey;
   RSAKey receiverPublicKey;

   public Sender(RSAKey rsaKey, RSAKey receiverPublicKey) {
       this.rsaKey = rsaKey;
       this.receiverPublicKey = receiverPublicKey;
   }


//This function demonstrates how customer will sign and encrypt the payload.

   public String packageMessage(String message) throws Exception {
       System.out.println("Message encryption starts with " + message);

       // Create a signature with a designated RSA2048 key pair.
       
       Signature signature = new Signature();
       String jwsToken = signature.sign(message, rsaKey);

       Cipher cipher = new Cipher();
       String jweToken = cipher.encrypt(jwsToken, receiverPublicKey.toRSAPublicKey());

       System.out.println("Success with encrypted payload: " + jweToken);

       return jweToken;
   }

}

Message receiver

import com.nimbusds.jose.JWSObject;
import com.nimbusds.jose.jwk.RSAKey;

//  This class is to simulate Socure's actions below:
//  1. Use Socure-generated RSA2048 private key to unwrap the AES key;
//  2. Use customer-generated RSA2048 public key to verify the customer's signature.
  
public class Receiver {
   RSAKey rsaKey;
   RSAKey senderPublicKey;

   public Receiver(RSAKey rsaKey, RSAKey senderPublicKey) {
       this.rsaKey = rsaKey;
       this.senderPublicKey = senderPublicKey;
   }

// This function demonstrates how Socure will decrypt the JWE token and verify the signature of customer.

   public String unpackageMessage(String encryptedMessage) throws Exception {
       System.out.println("Message decryption starts with: " + encryptedMessage);

       Signature signature = new Signature();
       Cipher cipher = new Cipher();
       String decryptedJwsToken = cipher.decrypt(encryptedMessage, rsaKey.toRSAPrivateKey());

       if (!signature.verify(decryptedJwsToken, senderPublicKey)) {
           throw new Exception("Error: the JKS token can not be accepted due to sender's signature verification failure.");
       }

       System.out.println("Success: The sender's JKS token is verified with the sender's signature.");
       JWSObject jwsObject = JWSObject.parse(decryptedJwsToken);
       return jwsObject.getPayload().toString();
   }

}