package visa.api;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.fasterxml.jackson.annotation.JsonInclude.Include;
import com.nimbusds.jose.*;
import com.nimbusds.jose.crypto.RSAEncrypter;
import com.nimbusds.jose.util.Base64;
import com.nimbusds.jose.util.IOUtils;
import java.io.ByteArrayInputStream;
import java.io.File;
import java.io.IOException;
import java.nio.charset.Charset;
import java.security.cert.Certificate;
import java.security.cert.CertificateException;
import java.security.cert.CertificateFactory;
import java.security.interfaces.RSAPublicKey;
public class EncryptionUtils {
private static final String BEGIN_CERT = "-----BEGIN CERTIFICATE-----";
private static final String END_CERT = "-----END CERTIFICATE-----";
// Update the path to your public certificate
private static String mleServerPublicCertificatePath = "C:\\Users\\supriya.mahajan\\Downloads\\server_cert.pem";
public static String getEncryptedPayload(Object payload, String keyId) throws CertificateException, JOSEException, IOException {
ObjectMapper mapper = new ObjectMapper();
mapper.setSerializationInclusion(Include.NON_NULL);
mapper.setSerializationInclusion(Include.NON_EMPTY);
String plainText = payload == null ? "" : mapper.writeValueAsString(payload);
JWEHeader.Builder headerBuilder = new JWEHeader.Builder(JWEAlgorithm.RSA_OAEP_256, EncryptionMethod.A128GCM);
headerBuilder.keyID(keyId);
headerBuilder.customParam("iat", System.currentTimeMillis());
JWEObject jweObject = new JWEObject(headerBuilder.build(), new Payload(plainText));
jweObject.encrypt(new RSAEncrypter(getRSAPublicKey()));
return "{\"encData\":\"" + jweObject.serialize() + "\"}";
}
/*
* Converts PEM file content to RSAPublicKey
*/
private static RSAPublicKey getRSAPublicKey() throws CertificateException, IOException {
String pemEncodedPublicKey = IOUtils.readFileToString(new File(mleServerPublicCertificatePath), Charset.forName("UTF-8"));
Base64 base64 = new Base64(pemEncodedPublicKey.replaceAll(BEGIN_CERT, "").replaceAll(END_CERT, "").trim());
Certificate cf = CertificateFactory.getInstance("X.509").generateCertificate(new ByteArrayInputStream(base64.decode()));
return (RSAPublicKey) cf.getPublicKey();
}
This is my EncryptionUtils.java file
package visa.api;
import visa.api.EncryptionUtils;
public class App {
public String getGreeting() {
return "Hello World!";
}
public static void main(String[] args) {
System.out.println(new App().getGreeting());
try {
// Sample payload and keyId
String payload = "{\n" +
" \"Envt\": {\n" +
" \"Card\": {\n" +
" \"CardTp\": \"PHYS\",\n" +
" \"XpryDt\": \"1230\",\n" +
" \"PAN\": \"4000123456781234\",\n" +
" \"Seed\": \"123456ABCDEF\",\n" +
" \"CardSeqNb\": 1\n" +
" }\n" +
" },\n" +
" \"Hdr\": {\n" +
" \"msgIdentfctn\": {\n" +
" \"clientId\": \"TEST_CLIENT_123\",\n" +
" \"correlatnId\": \"456987456\"\n" +
" },\n" +
" \"PrtcolVrsn\": \"VIP.1.1\"\n" +
" }\n" +
"}";
String keyId = "ccc10b08-04ae-4c4a-bdb9-0e8216148e9c";
// Encrypt the payload
String encryptedPayload = EncryptionUtils.getEncryptedPayload(payload, keyId);
System.out.println("Encrypted Payload: " + encryptedPayload);
} catch (Exception e) {
// Print stack trace for debugging
e.printStackTrace();
}
}
}
This is my App.java file
After running this code I am getting an encrypted payload.
That encrpyted code I am passing as postman request body as :
I am using the api to create new card and doing sandbox testing
Hi @supriya7768, Thank you for reaching out. An agent will look into this and get back to you soon. Until then, if any community member knows a solution, please feel free to reply in this thread.
Hey @supriya7768,
It looks like you're encountering a "Token validation failed" error when calling the Visa Card Service API. Here are some steps and tips to troubleshoot and resolve this issue:
1. Check Your API Credentials:
Ensure that the credentials you are using (API Key, Shared Secret) are correct and correspond to the sandbox environment.
2. X-App-Id:
This is the App ID generated when you created your project on the Visa Developer Platform. You can find this in the dashboard of your project under the "Credentials" section.
3. Certificate Configuration:
Ensure that you have correctly configured your certificates in Postman. You should add both the `cert.pem` and `key.pem` files in the "Certificates" section of Postman.
4. Authorization Header:
Make sure you are using the correct Base64 encoded username and password in the Authorization header. The format should be:
```
Authorization: Basic Base64Encode(username:password)
```
5. Headers:
Ensure you have the following headers in your request:
```http
X-App-Id: [Your X-App-Id]
keyID: [Your Key ID]
Accept: application/json
Content-Type: application/json
Authorization: Basic [Base64EncodedCredentials]
```
6. Payload Encryption:
Confirm that the payload encryption using the `EncryptionUtils` class is correct and matches the expected format by the API. Make sure that the `keyID` used in the encryption matches the `keyID` sent in the headers.
7. Timestamp:
The `iat` (issued at) parameter in the JWEHeader should be set to the current timestamp in milliseconds. Ensure this is correctly set as shown in your `EncryptionUtils` class.
8. Endpoint URL:
Confirm that you are using the correct sandbox endpoint URL:
```
https://sandbox.api.visa.com/connect/v1/cardServices/new
```
9. Example Code:
Here is an example of how you can structure your code and Postman request:
```java
// EncryptionUtils.java
package visa.api;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.fasterxml.jackson.annotation.JsonInclude.Include;
import com.nimbusds.jose.*;
import com.nimbusds.jose.crypto.RSAEncrypter;
import com.nimbusds.jose.util.Base64;
import com.nimbusds.jose.util.IOUtils;
import java.io.ByteArrayInputStream;
import java.io.File;
import java.io.IOException;
import java.nio.charset.Charset;
import java.security.cert.Certificate;
import java.security.cert.CertificateException;
import java.security.cert.CertificateFactory;
import java.security.interfaces.RSAPublicKey;
public class EncryptionUtils {
private static final String BEGIN_CERT = "-----BEGIN CERTIFICATE-----";
private static final String END_CERT = "-----END CERTIFICATE-----";
private static String mleServerPublicCertificatePath = "C:\\Users\\supriya.mahajan\\Downloads\\server_cert.pem";
public static String getEncryptedPayload(Object payload, String keyId) throws CertificateException, JOSEException, IOException {
ObjectMapper mapper = new ObjectMapper();
mapper.setSerializationInclusion(Include.NON_NULL);
mapper.setSerializationInclusion(Include.NON_EMPTY);
String plainText = payload == null ? "" : mapper.writeValueAsString(payload);
JWEHeader.Builder headerBuilder = new JWEHeader.Builder(JWEAlgorithm.RSA_OAEP_256, EncryptionMethod.A128GCM);
headerBuilder.keyID(keyId);
headerBuilder.customParam("iat", System.currentTimeMillis());
JWEObject jweObject = new JWEObject(headerBuilder.build(), new Payload(plainText));
jweObject.encrypt(new RSAEncrypter(getRSAPublicKey()));
return "{\"encData\":\"" + jweObject.serialize() + "\"}";
}
private static RSAPublicKey getRSAPublicKey() throws CertificateException, IOException {
String pemEncodedPublicKey = IOUtils.readFileToString(new File(mleServerPublicCertificatePath), Charset.forName("UTF-8"));
Base64 base64 = new Base64(pemEncodedPublicKey.replaceAll(BEGIN_CERT, "").replaceAll(END_CERT, "").trim());
Certificate cf = CertificateFactory.getInstance("X.509").generateCertificate(new ByteArrayInputStream(base64.decode()));
return (RSAPublicKey) cf.getPublicKey();
}
}
// App.java
package visa.api;
import visa.api.EncryptionUtils;
public class App {
public String getGreeting() {
return "Hello World!";
}
public static void main(String[] args) {
System.out.println(new App().getGreeting());
try {
String payload = "{\n" +
" \"Envt\": {\n" +
" \"Card\": {\n" +
" \"CardTp\": \"PHYS\",\n" +
" \"XpryDt\": \"1230\",\n" +
" \"PAN\": \"4000123456781234\",\n" +
" \"Seed\": \"123456ABCDEF\",\n" +
" \"CardSeqNb\": 1\n" +
" }\n" +
" },\n" +
" \"Hdr\": {\n" +
" \"msgIdentfctn\": {\n" +
" \"clientId\": \"TEST_CLIENT_123\",\n" +
" \"correlatnId\": \"456987456\"\n" +
" },\n" +
" \"PrtcolVrsn\": \"VIP.1.1\"\n" +
" }\n" +
"}";
String keyId = "ccc10b08-04ae-4c4a-bdb9-0e8216148e9c";
String encryptedPayload = EncryptionUtils.getEncryptedPayload(payload, keyId);
System.out.println("Encrypted Payload: " + encryptedPayload);
} catch (Exception e) {
e.printStackTrace();
}
}
}
```
Here is an example of the request body to be used in Postman:
```json
{
"encData": "eyJlbmMiOiJBMTI4R0NNIiwiaWF0IjoxNzI5NTAwNjE5OTk2LCJhbGciOiJSU0EtT0FFUC0yNTYiLCJraWQiOiJjY2MxMGIwOC0wNGFlLTRjNGEtYmRiOS0wZTgyMTYxNDhlOWMifQ.jf_HQbQxUe__x2FSx1zafEjo4Y8D2BT2gWpTMxfmRMh6jCYn9A7HRx_r2SrVcC_uy3gUWGTxPzmlA-H8kPhw2uZzEDGJrBU-Y7ZNPziBW370E8H9OqqM9rYmuX2gznHYr6j9cvu7zm80sVtSEOLjT9q2FEW3MeRYvsjl_v_3e0ie-kH9Q04Om9aj8RFoNkXriTWE1peOqDy448SBEytu2Uhz2LnoZZk5AAE3rzgcFnXlXfLeFUsqxkaP0y442UJSUcSdXr7cszVWG90SQMjVj4AArJdGyxIY-QQkmz8pfMpFlOzyUnCxMCHJP7m6uHbfU_FN7yE9GRxsGoGl5Y5IdA.tUhkGuOSb0rFZmAh.dYzsHlXPfeGNeMhMaRvBVG5A6L9Nr-VzDZjnqwinjbzP_pfTnfplM6fwZ0yx_pzCtPVQVjveL4Ac99ZDb2pgX2DESqeBWgWNWrmi58gRETtMdDt7ujDEhKOPvqIcv-mijbJzsgBSvCEhmpVxW0EGW2sWRBkHKSPw0wFS3s20jn5MprteT6VG1cGph17UKN7yGe2h6irGHkeIMjKzcll_f9K9ZaPolOx3lFhv4S3TxhhiE1rxtYtlmnJa-R4jZuH4EcfIdJ-nwxXdNhwYGwrGLiS85pGrKJS7ZA3gOJiZl94uVMgEuZgvgGhLIVfoIUFQq_RRogS8wIuwBtnFO8lr2IwmxTkVqAXvvGRLS0Xn_xgfSdBYG2LxWkiuoIa_pLye8KWUJ-gOK6bGYYkjkxOKovSIl1tQj1YdwRC_KqVhMdN0cW3HOn2W59FTpIbmPYkQSNjcjbNzxBYr9gcHgoo0FKQge-rfsMIukY7XXq1Prc1chdA.N0SYMkFGyfB5tfHIup5-2g"
}
```
Ensure that the `X-App-Id` and other headers are correctly set.