Creating a JWE Token
1. Setting Up for JWE
Libraries and Tools
To use JWE, you need appropriate libraries for your development environment. We recommend Nimbus JOSE+JWT for Java/Kotlin.
- Maven
- Gradle
- Gradle Kotlin DSL
Nimbus Dependency
<!-- https://mvnrepository.com/artifact/com.nimbusds/nimbus-jose-jwt -->
<dependency>
<groupId>com.nimbusds</groupId>
<artifactId>nimbus-jose-jwt</artifactId>
<version>9.40</version>
</dependency>
Nimbus Dependency
// https://mvnrepository.com/artifact/com.nimbusds/nimbus-jose-jwt
implementation 'com.nimbusds:nimbus-jose-jwt:9.40'
Nimbus Dependency
// https://mvnrepository.com/artifact/com.nimbusds/nimbus-jose-jwt
implementation("com.nimbusds:nimbus-jose-jwt:9.40")
2. Creating a JWE
The following example shows how to use the Nimbus library to create a JWE token with RSA-OAEP-256 encryption and A256GCM content encryption.
- Java
- Kotlin
Example JWE Creation
import com.nimbusds.jose.EncryptionMethod;
import com.nimbusds.jose.JWEAlgorithm;
import com.nimbusds.jose.JWEHeader;
import com.nimbusds.jose.JWEObject;
import com.nimbusds.jose.Payload;
import com.nimbusds.jose.crypto.RSAEncrypter;
import org.bouncycastle.jce.provider.BouncyCastleProvider;
import java.security.KeyFactory;
import java.security.Security;
import java.security.interfaces.RSAPublicKey;
import java.security.spec.X509EncodedKeySpec;
import java.util.Base64;
public class Main {
public static void main(String[] args) throws Exception {
// Add Bouncy Castle Provider
Security.addProvider(new BouncyCastleProvider());
// Replace with your recipient's public key string
String publicKeyPEM =
"-----BEGIN PUBLIC KEY-----\n" +
"MIIBIjANBgkqhkiG9w0 ... your key here\n" +
"-----END PUBLIC KEY-----";
// Remove the first and last lines and any whitespace
String publicKeyPEMFormatted = publicKeyPEM
.replace("-----BEGIN PUBLIC KEY-----", "")
.replace("-----END PUBLIC KEY-----", "")
.replaceAll("\\s", "");
// Decode the public key
byte[] keyBytes = Base64.getDecoder().decode(publicKeyPEMFormatted);
X509EncodedKeySpec keySpec = new X509EncodedKeySpec(keyBytes);
KeyFactory keyFactory = KeyFactory.getInstance("RSA", "BC");
RSAPublicKey recipientPublicKey = (RSAPublicKey) keyFactory.generatePublic(keySpec);
// Print the public key to verify
System.out.println("Loaded Public Key: " + recipientPublicKey);
// Building the JWE Header
JWEHeader header = new JWEHeader(JWEAlgorithm.RSA_OAEP_256, EncryptionMethod.A256GCM);
// Encrypting the Payload
Payload payload = new Payload("Sensitive data to be encrypted");
JWEObject jweObject = new JWEObject(header, payload);
// Encrypt with the recipient's public key
RSAEncrypter encrypter = new RSAEncrypter(recipientPublicKey);
jweObject.encrypt(encrypter);
// Generating the JWE Token
String jweToken = jweObject.serialize();
System.out.println("JWE Token: " + jweToken);
}
}
Example JWE Creation
import com.nimbusds.jose.EncryptionMethod
import com.nimbusds.jose.JWEAlgorithm
import com.nimbusds.jose.JWEHeader
import com.nimbusds.jose.JWEObject
import com.nimbusds.jose.Payload
import com.nimbusds.jose.crypto.RSAEncrypter
import org.bouncycastle.jce.provider.BouncyCastleProvider
import java.security.KeyFactory
import java.security.Security
import java.security.interfaces.RSAPublicKey
import java.security.spec.X509EncodedKeySpec
import java.util.*
fun main() {
// Add Bouncy Castle Provider
Security.addProvider(BouncyCastleProvider())
// Replace with your recipient's public key string
val publicKeyPEM = """
-----BEGIN PUBLIC KEY-----
MIIBIjANBgkqhkiG9w0 ... your key here
-----END PUBLIC KEY-----
""".trimIndent()
// Remove the first and last lines and any whitespace
val publicKeyPEMFormatted = publicKeyPEM
.replace("-----BEGIN PUBLIC KEY-----", "")
.replace("-----END PUBLIC KEY-----", "")
.replace("\\s".toRegex(), "")
// Decode the public key
val keyBytes = Base64.getDecoder().decode(publicKeyPEMFormatted)
val keySpec = X509EncodedKeySpec(keyBytes)
val keyFactory = KeyFactory.getInstance("RSA", "BC")
val recipientPublicKey = keyFactory.generatePublic(keySpec) as RSAPublicKey
// Print the public key to verify
println("Loaded Public Key: $recipientPublicKey")
// Replace with your recipient's public key
// val recipientPublicKey: RSAPublicKey = /* Load the recipient's public key */
// Building the JWE Header
val header = JWEHeader(JWEAlgorithm.RSA_OAEP_256, EncryptionMethod.A256GCM)
// Encrypting the Payload
val payload = Payload("Sensitive data to be encrypted")
val jweObject = JWEObject(header, payload)
// Encrypt with the recipient's public key
val encrypter = RSAEncrypter(recipientPublicKey)
jweObject.encrypt(encrypter)
// Generating the JWE Token
val jweToken = jweObject.serialize()
println("JWE Token: $jweToken")
}
3. Sending Encrypted Data to Figure's API
A JWE request requires a specific request body:
{ "encrypted": "<your-jwe-encrypted-request>" }
Example API Request
Example Request with JWE Request and Token
curl -X POST https://api.figure.com/example \
-H "apikey: <your-api-key>" \
-H "Content-Type: application/json" \
-d '{ "encrypted": "<your-jwe-encrypted-request>" }'
4. Decrypting a JWE (For Reference)
- Java
- Kotlin
JWE Header and Payload Decryption
import com.nimbusds.jose.JWEObject;
import com.nimbusds.jose.crypto.RSADecrypter;
import java.security.interfaces.RSAPrivateKey;
public class JWEDecryptionExample {
public static void main(String[] args) {
// The JWE token to decrypt
String jweToken = "your-jwe-token-here";
// Parse the JWE token
JWEObject jweObject = JWEObject.parse(jweToken);
// Extract and verify the JWE header
System.out.println("JWE Header: " + jweObject.getHeader());
// Load the private key
String privateKeyString = "-----BEGIN PRIVATE KEY-----\n" +
"MIIEvgIBADANBgkq ... your private key here ...\n" +
"-----END PRIVATE KEY-----";
String privateKeyFormatted = privateKeyString
.replace("-----BEGIN PRIVATE KEY-----", "")
.replace("-----END PRIVATE KEY-----", "")
.replaceAll("\\s", "");
byte[] privateKeyBytes = Base64.getDecoder().decode(privateKeyFormatted);
PKCS8EncodedKeySpec privateKeySpec = new PKCS8EncodedKeySpec(privateKeyBytes);
KeyFactory privatekeyFactory = KeyFactory.getInstance("RSA");
RSAPrivateKey privateKey = (RSAPrivateKey) privatekeyFactory.generatePrivate(privateKeySpec);
// Decrypt the encrypted data using the private key
RSADecrypter decrypter = new RSADecrypter(privateKey);
jweObject.decrypt(decrypter);
// Retrieve the payload
String payload = jweObject.getPayload().toString();
System.out.println("Decrypted Payload: " + payload);
}
}
JWE Header and Payload Decryption
import com.nimbusds.jose.JWEObject
import com.nimbusds.jose.crypto.RSADecrypter
import java.security.interfaces.RSAPrivateKey
fun main() {
// The JWE token to decrypt
val jweToken = "your-jwe-token-here"
// Parse the JWE token
val jweObject = JWEObject.parse(jweToken)
// Extract and verify the JWE header
println("JWE Header: ${jweObject.header}")
// Load the private key
val privateKeyString = """
-----BEGIN PRIVATE KEY-----
MIIEvgIBADANBgkq ... your private key here ...
-----END PRIVATE KEY-----
"""
val privateKeyFormatted = privateKeyString
.replace("-----BEGIN PRIVATE KEY-----", "")
.replace("-----END PRIVATE KEY-----", "")
.replace("\\s".toRegex(), "")
val privateKeyBytes = Base64.getDecoder().decode(privateKeyFormatted)
val privateKeySpec = PKCS8EncodedKeySpec(privateKeyBytes)
val privatekeyFactory = KeyFactory.getInstance("RSA")
val privateKey = privatekeyFactory.generatePrivate(privateKeySpec) as RSAPrivateKey
// Decrypt the encrypted data using the private key
val decrypter = RSADecrypter(privateKey)
jweObject.decrypt(decrypter)
// Retrieve the payload
val payload = jweObject.payload.toString()
println("Decrypted Payload: $payload")
}
5. Best Practices
Security Considerations
- Key Management: Store keys securely and rotate them regularly.
- Encryption Algorithms: Use strong, industry-standard algorithms (e.g., RSA-OAEP-256, A256GCM).
- Regular Updates: Keep your libraries and tools up to date to benefit from the latest security patches.
Debugging Tips
- Verify the correctness of your JWE header and payload.
- Ensure the recipient's public key is correctly configured for encryption.
6. Additional Resources
Conclusion
By following this guide, you will help us maintain the highest standards of security for data exchanged with Figure's API. We appreciate your commitment to protecting sensitive information and look forward to successful and secure integrations. If you need further assistance or specific examples, feel free to ask!