JWT Creation
JWT Fields
A valid generic transaction JWT must contain the below values. Additional fields may be required to complete an integration with some payment brands. Please review the payment brand's documentation for more details on if a payment brand needs additional fields.
Required Claims
Please note that each claim key is case sensitive.
Claim Name | Description |
---|---|
jti | JWT Id - A unique identifier for this JWT. This field should change each time a JWT is generated. |
iat | Issued At - A unix timestamp since epoch in seconds for when the JWT was generated. This value should be generated using UTC only. This allows us to determine how long a JWT has been around and whether we consider it expired or not. |
iss | Issuer - An identifier of who is issuing the JWT. We use this value to contain the Api Key identifier or name. |
OrgUnitId | The merchant SSO OrgUnitId |
Payload | The JSON data object being sent to Cardinal. This object is usually an Order object |
Optional Claims
The following claims are available for use but are not currently required for a valid JWT:
Claim Names | Description |
---|---|
ReferenceId | This is a merchant supplied identifier that can be used to match up data collected from Cardinal Cruise and Centinel. Centinel can then use data collected to enable rules or enhance the authentication request. |
ObjectifyPayload | A boolean flag that indicates how Centinel Api should consume the Payload claim. When set to true, this tells Centinel Api the Payload claim is an object. When set to false, the Payload claim is a stringified object. Some Jwt libraries do not support passing objects as claims, this allows those who only allow strings to use their libraries without customization |
exp | Expiration - The numeric epoch time that the JWT should be consider expired. This value is ignored if its larger than 2 hrs. By default we will not consider any JWT older than 2 hrs. |
Other Claims
The following claims are conditionally required when doing some transactional flows:
Claim Name | Description | Flow Required |
---|---|---|
ConfirmUrl | The merchant endpoint that will receive the post back from the payment brand that contains the Centinel API response JWT describing the result of redirecting to the payment brand. | Redirect |
JWT Payload Example
Below is an example of the JSON content of a basic JWT Payload where we are passing an object within the Payload claim:
{ "jti": "a5a59bfb-ac06-4c5f-be5c-351b64ae608e", "iat": 1448997865, "iss": "56560a358b946e0c8452365ds", "OrgUnitId": "565607c18b946e058463ds8r", "Payload": { "OrderDetails": { "OrderNumber": "0e5c5bf2-ea64-42e8-9ee1-71fff6522e15", "Amount": "1500", "CurrencyCode": "840" } }, "ObjectifyPayload": true, "ReferenceId": "c88b20c0-5047-11e6-8c35-8789b865ff15", "exp": 1449001465, "ConfirmUrl": 'https://mywebsite.com/confirmHandler' }
Below is an example of the JSON content of a basic JWT Payload where we are passing a string within the Payload claim:
{ "jti": "29311a10-5048-11e6-8c35-8789b865ff15", "iat": 1448997875, "iss": "56560a358b946e0c8452365ds", "OrgUnitId": "565607c18b946e058463ds8r", "Payload": "{\"OrderDetails\":{\"OrderNumber\":\"19ec6910-5048-11e6-8c35-8789b865ff15\",\"Amount\":\"1500\",\"CurrencyCode\":\"840\"}}", "ObjectifyPayload" false "ReferenceId": "074fda80-5048-11e6-8c35-8789b865ff15" "exp":1449001465, "ConfirmUrl": 'https://mywebsite.com/confirmHandler' }
Code Samples
The below code samples are to provide you with a basic idea on how to generate JWT's within a few languages.
We do not recommend using these samples unmodified in a production environment. They are intended as examples only.
Generating a Server JWT in .NET
We recommend using an existing third party library to assist you in generating a JWT. The JWT.io website contains a list of libraries with their feature sets. Check it out here. In the below sample we will focus on using this JWT (GitHub.com) library.
Dependencies
When using nuget you can grab the JWT library by installing the package 'JsonWebTokens'. It has been reported that some versions of .Net will need to install an additional dependency 'System.Security.Cryptography.Primitives' for 'JsonWebTokens' to work properly.
// This sample code was written using the JSON Web Token Handler library. using System.Configuration; using System.Web.Mvc; using CardinalCruiseDemoSite.Helpers; using CardinalCruiseDemoSite.Models.View; namespace CardinalCruiseDemoSite.Controllers { public class HomeController : Controller { private readonly JwtHelper _jwtHelper = new JwtHelper(); public ActionResult Index() { var apiKey = ConfigurationManager.AppSettings["APIKey"]; var apiIdentifier = ConfigurationManager.AppSettings["APIIdentifier"]; var orgUnitId = ConfigurationManager.AppSettings["OrgUnitId"]; var jwt = _jwtHelper.GenerateJwt(apiKey, apiIdentifier, orgUnitId); return View(new CardinalCruiseViewModel {JWT = jwt}); } } }
namespace CardinalCruiseDemoSite.Models.View { public class CardinalCruiseViewModel { public string JWT { get; set; } } }
This is an example of a JWT object class.
using System; using System.Collections.Generic; using CardinalCruiseDemoSite.Models; using JWT; namespace CardinalCruiseDemoSite.Helpers { public class JwtHelper { public string GenerateJwt(string apiKey, string apiIdentifier, string orgUnitId) { var payload = new Dictionary<string, object> { {"exp", DateTime.UtcNow.AddDays(365).ToUnixTime()}, {"iat", DateTime.UtcNow.ToUnixTime()}, {"jti", Guid.NewGuid()}, {"iss", apiIdentifier}, {"OrgUnitId", orgUnitId}, { "Payload", new Order { OrderDetails = new OrderDetails { OrderNumber = Guid.NewGuid().ToString() } } } }; return JsonWebToken.Encode(payload, apiKey, JwtHashAlgorithm.HS256); } } }
It is important that you generate the JWT expiration using UNIX time. We recommend using a library such as NodaTime from NodaTime.org to help with this. If you are unable to use a third party library, here is a helper function you may use (this is used in the example above):
using System; namespace CardinalCruiseDemoSite.Helpers { public static class DateTimeHelper { public static long ToUnixTime(this DateTime date) { var epoch = new DateTime(1970, 1, 1, 0, 0, 0, DateTimeKind.Utc); return Convert.ToInt64((date - epoch).TotalSeconds); } } }
Generating a Server JWT in Java
We recommend using an existing third party library to assist you in generating a JWT. The JWT.io website contains a list of approved libraries, with their feature sets. Check it out here.
// This sample code was written using the Java JWT // library (https://github.com/jwtk/jjwt) found at JWT.io import io.jsonwebtoken.JwtBuilder; import io.jsonwebtoken.Jwts; import io.jsonwebtoken.SignatureAlgorithm; import java.security.Key; import java.util.Date; import java.util.UUID; import javax.crypto.spec.SecretKeySpec; public class generateJWT { public static String apiKey = ""; public static String apiIdentifier = ""; public static String orgUnitId = ""; // Sample method to construct a JWT public static String createJWT(String jwtId, long ttlMillis, Order orderObject) { // The JWT signature algorithm we will be using to sign the token SignatureAlgorithm signatureAlgorithm = SignatureAlgorithm.HS256; long nowMillis = System.currentTimeMillis(); Date now = new Date(nowMillis); // We will sign our JWT with our API Key byte[] apiKeySecretBytes = apiKey.getBytes(); Key signingKey = new SecretKeySpec(apiKeySecretBytes, signatureAlgorithm.getJcaName()); // Let's set the JWT Claims JwtBuilder builder = Jwts.builder() .setId(jwtId) .setIssuedAt(now) .setIssuer(apiIdentifier) .claim("OrgUnitId", orgUnitId) .claim("Payload", orderObject) .signWith(signatureAlgorithm, signingKey); // Add the expiration or TTL (Time To Live) for this JWT if (ttlMillis > 0) { long expMillis = nowMillis + ttlMillis; Date exp = new Date(expMillis); builder.setExpiration(exp); } // Builds the JWT and serializes it to a compact, URL-safe string return builder.compact(); } }
Generating a Server JWT in PHP
We recommend using an existing third party library to assist you in generating a JWT. The JWT.io website contains a list of approved libraries, with their feature sets. Check it out here.
<?php /* composer.json Example: { "require": { "lcobucci/jwt": "3.1.0" // Note: Requires PHP 7 } } */ require "vendor/autoload.php"; // Autoload.php is generated by Composer use Lcobucci\JWT\Builder; use Lcobucci\JWT\Signer\Hmac\Sha256; $GLOBALS['ApiKey'] = '[INSERT_API_KEY_HERE]'; $GLOBALS['ApiId'] = '[INSERT_API_KEY_ID_HERE]'; $GLOBALS['OrgUnitId'] = '[INSERT_ORG_UNIT_ID_HERE]'; $_SESSION['TransactionId'] = uniqid(); $_SESSION['Order'] = array( "OrderDetails" => array( "OrderNumber" => 'ORDER-' . strval(mt_rand(1000, 10000)), "Amount" => '1500', "CurrencyCode" => '840' ) ); function generateJwt($orderTransactionId, $orderObj){ $currentTime = time(); $expireTime = 3600; // expiration in seconds - this equals 1hr $token = (new Builder())->setIssuer($GLOBALS['ApiId']) // API Key Identifier (iss claim) ->setId($orderTransactionId, true) // The Transaction Id (jti claim) ->setIssuedAt($currentTime) // Configures the time that the token was issued (iat claim) ->setExpiration($currentTime + $expireTime) // Configures the expiration time of the token (exp claim) ->set('OrgUnitId', $GLOBALS['OrgUnitId']) // Configures a new claim, called "OrgUnitId" ->set('Payload', $_SESSION['Order']) // Configures a new claim, called "Payload", containing the OrderDetails ->set('ObjectifyPayload', true) ->sign(new Sha256(), $GLOBALS['ApiKey']) // Sign with API Key ->getToken(); // Retrieves the generated token return $token; // The JWT String } echo generateJwt($_SESSION['TransactionId'], $_SESSION['Order']); ?>