REST API

JSON Web Token Authentication

This topic provides information about authenticating Cybersource REST API requests with JSON Web Token (JWT) authentication.
For code that you can use to authenticate REST API requests, see the SDK for your language:
For information about generating JWT authentication P12 and PKCS12 keys, see "Create a P12 Certificate for JSON Web Token Authentication."
For information about converting Cybersource P12 or PKCS12 keys, see "Convert Cybersource P12 or PKCS12 to Another KeyStore Type."
 
 
JWT Token
Field Name
Description
Example
JWT Token
With All three components
JWT header
,
claim set
, and
Signature
, concatenate the components into a valid JWT authorization token.
JWT token = JWT
header.Claim set.signature
 
Combine the header and payload and signature with periods (.) separating them.
Example:
JWT Token = base64url( JWT header ) + “.” + base64url( Payload ) + “.” + base64url( Signature )
// Sample JWT header
eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9
// Sample PayLoad
eyJ1c2VySWQiOiJiMDhmODZhZi0zNWRhLTQ4ZjItOGZhYi1jZWYz OTA0NjYwYmQifQ
// Sample signature
-xN_h82PHVTCMA9vdoHrcZxH-x5mb11y1537t3rGzcM
// Sample JWT Token
eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJ1c2VySWQiOiJiMDhm ODZhZi0zNWRhLTQ4ZjItOGZhYi1jZWYzOTA0NjYwYmQifQ.-xN_h82PHVTCMA9vdoHrcZxH-x5mb11y1537t3rGzcM
 
 
JWT Header
Field Name
Description
Example
x5c
The
x5c
(X.509 certificate chain) Header Parameter contains the X.509 public key certificate or certificate chain corresponding to the key(.p12) used to digitally sign the token.
This is a required field.
MIICZTCCAc6gAwIBAg…Emj0F35Ew2ek4VezUXnZ/SMLvWEA6DG2sjSFCCuIot3mLJ3lI4AQSQSBSazhQec75Rk=
alg
The signing algorithm used.
This is a required field.
alg: RS256
v-c-merchant-id
Merchant ID assigned in the Business Center.
Required for merchant transactions.
Required for partners sending transactions of behalf of merchants.
v-c-merchant-id: merchant_id
 
 
JWT Payload/Claim Set
Field Name
Description
Example
iat
The date and time of message origin. The date can be in any format for a time zone.
Date formatting as defined by RFC7231: 
http://tools.ietf.org/html/rfc7231#section-7.1.1.1
String gmtDateTime = DateTimeFormatter.RFC_1123_DATE_TIME.format(         ZonedDateTime.now(ZoneId.of("GMT")));
This is a required field.
iat: Thru, 15 June 2017 08:12:31 GMT
Digest
Digest of JSON payload. The digest is Base64-encoded.
The
digest
field should not be passed in the JWT Header for a GET call.
example_payload:
{   "clientReferenceInformation" : {     "code" : "TC50171_3"   },   "orderInformation" : {     "amountDetails" : {       "totalAmount" : "102.21",       "currency" : "USD"     }   } }
SHA256_hash_of_example_payload =
2b4fee10da8c5e1feaad32b014021e079fe4afcf06af223004af944011a7cb65c
# The hash has Base64 encoded Digest header in RFC3230 defined format of "Digest:
BASE64(SHA256_hash_of_example_payload)“
= tP7hDajF4f6q0ysBQCHgef5K/PBq8iMASvlEARp8tl=
Digest: tP7hDajF4f6q0ysBQCHgef5K/PBq8iMASvlEARp8tl=
Code Snippet:
MessageDigest signatureString = MessageDigest.getInstance("SHA-256");byte[] digestBytes = signatureString.digest(messageBody.getBytes());String bluePrint = Base64.getEncoder().encodeToString(digestBytes);
digestAlgorithm
The signature algorithm you are using. For asymmetric keys, use a SHA-256 hash.
The
digestAlgorithm
field should not be passed in the JWT Header for a GET call.
"digestAlgorithm":  SHA-256
 
 
JWT Signature
Field Name
Description
Example
JWT Signature
The JWT header and the claim set created in previous steps is Base64-encoded. Join the resulting encoded strings together with a period (.) in between them. In our pseudo code, this joined string is assigned to data.
To get the JWT signature, the data string is signed with RS256 with the private key using the signing algorithm specified in the JWT header. Signature String is then encoded with Base64-encoded before creating final token.
data = base64urlEncode( JWT header ) + “.” + base64urlEncode( Claimset )
signature = RS256Hash( data, private_key ) ;
signature = eyJ2LWMtbWVyY2hhbn…WYQNLMOApxv6-DdcJZK4L9mLRc3gFb1kTFvodNEI6M0GeyoFp-b9PNG32TLQITYfWmZEbTZExgQHXGwwqo
 
 
Sample Code
Format/Example
Encoding and hashing digest:
if(requestBody != null && !requestBody.isEmpty()) {      MessageDigest jwtBody = MessageDigest.getInstance("SHA-256");      byte[] Headers = jwtBody.digest(requestBody.getBytes());      e = Base64.getEncoder().encodeToString(Headers);  }
Preparing payload:
String jwtBody = "{\n \"digest\":\"" + e + "\",\n \"digestAlgorithm\":\"SHA-256\",\n \"iat\":\"" + DateTimeFormatter.RFC_1123_DATE_TIME.format(ZonedDateTime.now(ZoneId.of("GMT"))) + "\"\n} \n\n"; HashMap customHeaders = new HashMap(); customHeaders.put(v-c-merchant-id, merchantConfig.getMerchantID()); String jwsSignatureValue = sign(jwtBody, rsaPrivateKey, x509Certificate, customHeaders);
Generating JWT Token—Header, Payload, and Signature:
private sign(String content, PrivateKey privateKey, X509Certificate x509Certificate, Map<String, ? extends Object> customHeaders) {     if(!this.isNullOrEmpty(content) && x509Certificate != null && privateKey != null) {         String serialNumber = null;         String serialNumberPrefix = "SERIALNUMBER=";         String principal = x509Certificate.getSubjectDN().getName().toUpperCase();         int beg = principal.indexOf(serialNumberPrefix);         if(beg >= 0) {                 int x5cBase64List = principal.indexOf(",", beg);                 if(x5cBase64List == -1) {                     x5cBase64List = principal.length();                 }                 serialNumber = principal.substring(beg + serialNumberPrefix.length(), x5cBase64List);         } else {                 serialNumber = x509Certificate.getSerialNumber().toString();         }         ArrayList x5cBase64List1 = new ArrayList();         try {           x5cBase64List1.add(Base64.encode(x509Certificate.getEncoded()));         } catch (CertificateEncodingException var16) {           logger.error("can\'t signAndEncrypt the payload", var16);           return null;         }         RSAPrivateKey rsaPrivateKey = (RSAPrivateKey)privateKey;         Payload payload = new Payload(content);         JWSHeader jwsHeader = (new com.nimbusds.jose.JWSHeader.Builder(JWSAlgorithm.RS256)).customParams(customHeaders).keyID(serialNumber).x509CertChain(x5cBase64List1).build();         JWSObject jwsObject = new JWSObject(jwsHeader, payload);         try {             RSASSASigner joseException = new RSASSASigner(rsaPrivateKey);             jwsObject.sign(joseException);             if(!jwsObject.getState().equals(com.nimbusds.jose.JWSObject.State.SIGNED)) {                 logger.error("Payload signing failed.");                 return null;             } else {                 return jwsObject;             }         } catch (JOSEException var15) {             logger.error("can\'t signAndEncrypt the payload", var15);             return null;         }     } else {         logger.error("empty or null content or Private key or public certificate is null");         return null;     } }

Convert Cybersource P12 or PKCS12 to Another KeyStore Type

Use the Java API to convert the Cybersource PKCS12 file into another keystore type. Use the Bouncy Castle JCE cryptography provider to do the conversion. Bouncy Castle JCE understands the multi certificate PKCS12 format.
The following code snippet uses the Bouncy Castle JCE API to access and convert the Cybersource PKCS12.
 private static X509Certificate initializeCertificate(MerchantConfig merchantConfig) throws CertificateException, NoSuchAlgorithmException, IOException, KeyStoreException, UnrecoverableEntryException, ConfigException {         if(merchantConfig != null && merchantConfig.getKeyAlias() != null && merchantConfig.getKeyFile() != null) {             KeyStore merchantKeyStore = KeyStore.getInstance("PKCS12", new BouncyCastleProvider());             merchantKeyStore.load(new FileInputStream(merchantConfig.getKeyFile()), merchantConfig.getKeyPassword().toCharArray());             String merchantKeyAlias = null;             Enumeration enumKeyStore = merchantKeyStore.aliases();             while(enumKeyStore.hasMoreElements()) {                 merchantKeyAlias = (String)enumKeyStore.nextElement();                 if(merchantKeyAlias.contains(merchantConfig.getKeyAlias())) {                     break;                 }             }             PrivateKeyEntry keyEntry = (PrivateKeyEntry)merchantKeyStore.getEntry(merchantKeyAlias, new PasswordProtection(merchantConfig.getKeyPassword().toCharArray()));             return (X509Certificate)keyEntry.getCertificate();         } else {             throw new ConfigException("merchant config fields missing: key alias, key file");         }     }     private static RSAPrivateKey initializePrivateKey(MerchantConfig merchantConfig) throws CertificateException, NoSuchAlgorithmException, IOException, KeyStoreException, UnrecoverableEntryException, ConfigException {         if(merchantConfig != null && merchantConfig.getKeyAlias() != null && merchantConfig.getKeyFile() != null) {             KeyStore merchantKeyStore = KeyStore.getInstance("PKCS12", new BouncyCastleProvider());             merchantKeyStore.load(new FileInputStream(merchantConfig.getKeyFile()), merchantConfig.getKeyPassword().toCharArray());             String merchantKeyAlias = null;             Enumeration enumKeyStore = merchantKeyStore.aliases();             while(enumKeyStore.hasMoreElements()) {                 merchantKeyAlias = (String)enumKeyStore.nextElement();                 if(merchantKeyAlias.contains(merchantConfig.getKeyAlias())) {                     break;                 }             }             PrivateKeyEntry keyEntry = (PrivateKeyEntry)merchantKeyStore.getEntry(merchantKeyAlias, new PasswordProtection(merchantConfig.getKeyPassword().toCharArray()));             return (RSAPrivateKey)keyEntry.getPrivateKey();         } else {             throw new ConfigException("merchant config fields missing: key alias, key file");         }     }