Payload Encryption (Optional)
Payload encryption enables secure, tamper-proof communication between clients and Socure’s RiskOS™ using industry-standard JWE (JSON Web Encryption) and JWS (JSON Web Signature) protocols.
This feature ensures confidentiality, integrity, and compliance when transmitting sensitive identity data.
Supported endpoints
Payload encryption is supported on the following RiskOS™ endpoints.
| Service | Supported Endpoints |
|---|---|
| Evaluation | POST /api/evaluationPOST /api/evaluation/:versionPATCH /api/evaluation/:eval_id |
| DocV | POST /api/docv/uploadPATCH /api/docv/upload/:docv_transaction_token |
Required headers
Encryption is triggered by the X-Payload-Encrypted: true header.
Authorization: Bearer YOUR_API_KEY
Content-Type: application/json
Accept: application/json
X-Payload-Encrypted: trueIf the X-Payload-Encrypted header is omitted, the endpoint expects a standard JSON payload.
Request format
All supported endpoints require the same encrypted request structure:
{
"encrypted_request": "<JWE_STRING>"
}The encrypted_request value must be a properly constructed JWE
compact serialization string.
Response format
Evaluation API response
{
"eval_id": "fd2a9785-554c-46be-a36f-e9443eefa380",
"encrypted_response": "<JWE_STRING>"
}DocV API response
{
"docv_previous_reference_id": "fd2a9785-554c-46be-a36f-e9443eefa380",
"encrypted_response": "<JWE_STRING>"
}The encrypted_response field contains a signed and encrypted JWE
payload.
Supported cryptographic standards
Payload encryption uses a dual-layer model:
- Digital Signature (JWS) -- Ensures integrity and authenticity.
- Encryption (JWE) -- Ensures confidentiality.
| Layer | Algorithm |
|---|---|
| Signing | RS256 (RSA + SHA256) |
| Key Encryption | RSA_OAEP_256 |
| Content Encryption | A256GCM (AES-GCM 256-bit) |
Encryption flow
Customer → Socure (request)
- Sign the payload using your private RSA key with
RS256. - Generate a unique 256-bit AES Content Encryption Key (CEK).
- Encrypt the signed payload using
A256GCM. - Encrypt the CEK using Socure's public RSA key with
RSA_OAEP_256. - Serialize the components into a JWE compact string.
- Send the JWE string in the request body:
{
"encrypted_request": "<JWE_STRING>"
}Socure then:
- Decrypts the CEK using its private key
- Decrypts the payload using the CEK
- Verifies the signature using your public key
Socure → Customer (response)
- Socure signs the response payload using its private RSA key.
- Generates a unique 256-bit CEK.
- Encrypts the signed payload using
A256GCM. - Encrypts the CEK using your public RSA key.
- Returns:
{
"eval_id": "<uuid or docv reference>",
"encrypted_response": "<JWE_STRING>"
}You must:
- Decrypt the CEK with your private key.
- Decrypt the payload.
- Verify Socure's signature using Socure's public key.
Key management requirements
-
Unique Keys Required
Encryption keys from Socure ID+ cannot be reused. A dedicated X.509 certificate exchange must be completed specifically for your RiskOS™ account. -
Single Key Pair per Account
RiskOS™ does not support multiple key pairs for different use cases within the same account. -
Optional Encryption
Encryption is enforced only whenX-Payload-Encrypted: trueis present.
Prerequisites for payload encryption
Ensure the following requirements are met before enabling payload encryption:
Encryption will not function until the certificate exchange is completed.
API responses
Success — HTTP 200:
200:Indicates successful processing of the encrypted payload.
{
"eval_id": "123456-abcdef-123456",
"encrypted_response": "<JWE_String>"
}Error — HTTP 400:
400:Indicates encryption or signature validation failure.
{
"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.
Common error messages:
- Payload encryption is not supported for this API key
- Payload format is not supported
- Encrypted payload is not in JWE format
- Signed payload is not in JWS format
- Payload decryption failed
- Payload signature could not be verified
Error — HTTP 500:
500:The payload was successfully verified, but Socure failed during response encryption.
{
"eval_id": "123456-abcdef-123456",
"error": "The encrypted payload is verified with success, however, server has internal problems to handle response encryption"
}Reference implementation (Java example)
This example demonstrates signing and encryption using the Nimbus JOSE + JWT library. Any standards-compliant JWE/JWS implementation may be used.
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();
}
}Updated about 1 month ago
