Learn how to encrypt and decrypt payloads using JWE tokens
Overview
The Modulus Labs QR API uses JWE (JSON Web Encryption) tokens to encrypt request and response payloads. This ensures that sensitive payment data is protected and maintains integrity throughout the entire transaction lifecycle.
What is JWE? JSON Web Encryption is a standard for encrypting data in a compact, URL-safe format. It ensures that the payload cannot be read or modified during transit.
Why JWE Encryption?
Data Protection
Sensitive payment information is encrypted end-to-end
Integrity Verification
Any tampering with the token will cause verification to fail
Compliance
Meets security standards for financial transactions
Standardized
Uses industry-standard encryption algorithms
Encryption Specifications
The QR API requires specific encryption algorithms for JWE tokens:
Parameter
Value
Description
Content Encryption
A256CBC-HS512
AES-256-CBC with HMAC SHA-512
Key Wrap Algorithm
A256KW
AES-256 Key Wrap
Content Type
application/json
JSON payload format
Your Encryption Key
Along with your Secret Key, Modulus Labs will provide you with an Encryption Key for JWE operations:
REPLACE_WITH_YOUR_ENCRYPTION_KEY
Store your Encryption Key securely! Never commit it to version control or expose it in client-side code.
Recommended Libraries
Use these well-tested libraries for creating and decrypting JWE tokens:
const jose = require('jose');// Your encryption key from Modulus Labsconst encryptionKey = 'REPLACE_WITH_YOUR_ENCRYPTION_KEY';// Convert the key to the proper formatconst secretKey = Buffer.from(encryptionKey, 'base64');// Your payment dataconst payload = { activationCode: 'A9X4-B7P2-Q6Z8-M3L5', currency: 'PHP', amount: '98.00', merchantReferenceNumber: '5e91bc6c-f7e2-4a39-ae0e-5e93985c94a4'};// Create the JWE tokenconst jwe = await new jose.CompactEncrypt( new TextEncoder().encode(JSON.stringify(payload))) .setProtectedHeader({ alg: 'A256KW', enc: 'A256CBC-HS512' }) .encrypt(secretKey);console.log('JWE Token:', jwe);// Result: eyJhbGciOiJBMjU2S1ciLCJlbmMiOiJBMjU2Q0JDLUhTNTEyIn0...
from jose import jweimport json# Your encryption key from Modulus Labsencryption_key = 'REPLACE_WITH_YOUR_ENCRYPTION_KEY'# Your payment datapayload = { 'activationCode': 'A9X4-B7P2-Q6Z8-M3L5', 'currency': 'PHP', 'amount': '98.00', 'merchantReferenceNumber': '5e91bc6c-f7e2-4a39-ae0e-5e93985c94a4'}# Create the JWE tokenjwe_token = jwe.encrypt( json.dumps(payload), encryption_key, algorithm='A256KW', encryption='A256CBC-HS512')print('JWE Token:', jwe_token)
<?phpuse Jose\Component\Core\AlgorithmManager;use Jose\Component\Core\JWK;use Jose\Component\Encryption\Algorithm\KeyEncryption\A256KW;use Jose\Component\Encryption\Algorithm\ContentEncryption\A256CBCHS512;use Jose\Component\Encryption\Compression\CompressionMethodManager;use Jose\Component\Encryption\JWEBuilder;use Jose\Component\Encryption\Serializer\CompactSerializer;// Your encryption key from Modulus Labs$encryptionKey = 'REPLACE_WITH_YOUR_ENCRYPTION_KEY';// Create JWK from your key$jwk = new JWK([ 'kty' => 'oct', 'k' => $encryptionKey]);// Algorithm managers$keyEncryptionAlgorithmManager = new AlgorithmManager([ new A256KW(),]);$contentEncryptionAlgorithmManager = new AlgorithmManager([ new A256CBCHS512(),]);// Your payment data$payload = json_encode([ 'activationCode' => 'A9X4-B7P2-Q6Z8-M3L5', 'currency' => 'PHP', 'amount' => '98.00', 'merchantReferenceNumber' => '5e91bc6c-f7e2-4a39-ae0e-5e93985c94a4']);// Build the JWE$jweBuilder = new JWEBuilder( $keyEncryptionAlgorithmManager, $contentEncryptionAlgorithmManager, new CompressionMethodManager());$jwe = $jweBuilder ->create() ->withPayload($payload) ->withSharedProtectedHeader([ 'alg' => 'A256KW', 'enc' => 'A256CBC-HS512', ]) ->addRecipient($jwk) ->build();// Serialize to compact format$serializer = new CompactSerializer();$token = $serializer->serialize($jwe, 0);echo 'JWE Token: ' . $token;
using Jose;// Your encryption key from Modulus Labsvar encryptionKey = "REPLACE_WITH_YOUR_ENCRYPTION_KEY";var key = Base64UrlDecode(encryptionKey);// Base64URL decoding helperstatic byte[] Base64UrlDecode(string base64Url){ var base64 = base64Url.Replace('-', '+').Replace('_', '/'); switch (base64.Length % 4) { case 2: base64 += "=="; break; case 3: base64 += "="; break; } return Convert.FromBase64String(base64);}// Your payment datavar payload = new{ activationCode = "A9X4-B7P2-Q6Z8-M3L5", currency = "PHP", amount = "98.00", merchantReferenceNumber = "5e91bc6c-f7e2-4a39-ae0e-5e93985c94a4"};// Create the JWE tokenvar jweToken = JWT.Encode( payload, key, JweAlgorithm.A256KW, JweEncryption.A256CBC_HS512);Console.WriteLine($"JWE Token: {jweToken}");
# Note: JWE encryption requires a library/tool# Use one of the language examples below to encrypt your payload,# then use the encrypted token with cURLENCRYPTED_TOKEN="eyJhbGciOiJBMjU2S1ciL..."curl -X POST https://qrph.sbx.moduluslabs.io/v1/pay/qr \ -u sk_YOUR_SECRET_KEY: \ -H "Content-Type: application/json" \ -d "{\"Token\": \"$ENCRYPTED_TOKEN\"}"
const jose = require('jose');// Your encryption keyconst encryptionKey = 'REPLACE_WITH_YOUR_ENCRYPTION_KEY';const secretKey = Buffer.from(encryptionKey, 'base64');// The JWE token from the responseconst jweToken = response.Token;// Decrypt the tokenconst { plaintext } = await jose.compactDecrypt(jweToken, secretKey);// Parse the payloadconst payload = JSON.parse(new TextDecoder().decode(plaintext));console.log('Decrypted payload:', payload);// {// "id": "0ce32626-08cf-405c-adab-6d384a8871da",// "qrBody": "LAawP8GKxWCwWA1gf4MVisVgsBrA+wIvFYrFYDGB9gBeLxWKxGMD6AC8Wi8ViMYD1AV4sFovFYgDrA7xYLBaLxQDWB3ixWCwWiwGsD/BisVgsFgNYH+DFYrFYLAawPsCLxWKxWAxgfYAX8VisRjA+gAvFovFYjGA9QFeLBaLxf/fXh0LAAAAAAzytx7GnpKIgYABYCBgABgIGAAGAgaAgYABYCBgABgIGAAGAgaAgYABYBC6Qa/HfkoA6gAAAABJRU5ErkJggg=="// }
from jose import jweimport json# Your encryption keyencryption_key = 'REPLACE_WITH_YOUR_ENCRYPTION_KEY'# The JWE token from the responsejwe_token = response['Token']# Decrypt the tokendecrypted_data = jwe.decrypt(jwe_token, encryption_key)# Parse the payloadpayload = json.loads(decrypted_data)print('Decrypted payload:', payload)
<?php// Decrypt using the same setup as encryption$decrypted = $jweLoader->loadAndDecryptWithKey( $jweToken, $jwk, $recipient);// Get the payload$payload = $decrypted->getPayload();$data = json_decode($payload, true);print_r($data);
using Jose;// Your encryption keyvar encryptionKey = "REPLACE_WITH_YOUR_ENCRYPTION_KEY";var key = Base64UrlDecode(encryptionKey);// The JWE token from the responsevar jweToken = response.Token;// Decrypt the tokenvar decryptedJson = JWT.Decode(jweToken, key);var payload = JsonConvert.DeserializeObject<dynamic>(decryptedJson);Console.WriteLine($"Transaction ID: {payload.id}");Console.WriteLine($"QR Body: {payload.qrBody}");
# Decryption requires a library/tool# Use one of the language examples to decrypt the JWE response token# The token from the response body:echo "Use Node.js, Python, PHP, Go, Java, or C# to decrypt the response Token"
package mainimport ( "encoding/base64" "encoding/json" "fmt" "github.com/lestrrat-go/jwx/v2/jwa" "github.com/lestrrat-go/jwx/v2/jwe")func main() { encryptionKey := "REPLACE_WITH_YOUR_ENCRYPTION_KEY" keyBytes, _ := base64.RawURLEncoding.DecodeString(encryptionKey) // The JWE token from the response jweToken := "eyJhbGciOiJBMjU2S1ciL..." // response.Token // Decrypt the token decrypted, _ := jwe.Decrypt([]byte(jweToken), jwe.WithKey(jwa.A256KW, keyBytes)) // Parse the payload var payload map[string]interface{} json.Unmarshal(decrypted, &payload) fmt.Printf("Transaction ID: %s\n", payload["id"]) fmt.Printf("QR Body: %s\n", payload["qrBody"])}
import com.nimbusds.jose.*;import com.nimbusds.jose.crypto.AESDecrypter;import com.nimbusds.jose.jwk.OctetSequenceKey;import com.fasterxml.jackson.databind.ObjectMapper;import java.util.*;public class DecryptExample { public static void main(String[] args) throws Exception { String encryptionKey = "REPLACE_WITH_YOUR_ENCRYPTION_KEY"; byte[] keyBytes = Base64.getUrlDecoder().decode(encryptionKey); OctetSequenceKey jwk = new OctetSequenceKey.Builder(keyBytes).build(); // The JWE token from the response String jweToken = "eyJhbGciOiJBMjU2S1ciL..."; // response.getToken() // Decrypt the token JWEObject jweObject = JWEObject.parse(jweToken); jweObject.decrypt(new AESDecrypter(jwk)); String decryptedJson = jweObject.getPayload().toString(); Map<String, String> payload = new ObjectMapper().readValue(decryptedJson, Map.class); System.out.println("Transaction ID: " + payload.get("id")); System.out.println("QR Body: " + payload.get("qrBody")); }}
Response Types
The API returns different response formats based on the request status:
# Complete flow requires a language with JWE support for encryption/decryption# Use cURL only for the HTTP request step:ENCRYPTED_TOKEN="eyJhbGciOiJBMjU2S1ciL..."curl -X POST https://qrph.sbx.moduluslabs.io/v1/pay/qr \ -u $MODULUS_SECRET_KEY: \ -H "Content-Type: application/json" \ -d "{\"Token\": \"$ENCRYPTED_TOKEN\"}"# Decrypt the response Token using your preferred language