diff --git a/commerce_authnet.libraries.yml b/commerce_authnet.libraries.yml
index 0fe801a..4aa9e61 100644
--- a/commerce_authnet.libraries.yml
+++ b/commerce_authnet.libraries.yml
@@ -56,3 +56,19 @@ form-visa-checkout-production:
   version: 1
   js:
     "https://assets.secure.checkout.visa.com/checkout-widget/resources/js/integration/v1/sdk.js": { type: external, attributes: { charset: utf-8 } }
+
+cardinalcruise-dev:
+  version: 1
+  header: true
+  js: 
+    "https://songbirdstag.cardinalcommerce.com/edge/v1/songbird.js": { type: external, attributes: { charset: utf-8 } }
+  dependencies:
+  - commerce_authnet/form-accept
+
+cardinalcruise:
+  version: 1
+  header: true
+  js: 
+    "https://songbird.cardinalcommerce.com/edge/v1/songbird.js": { type: external, attributes: { charset: utf-8 } }
+  dependencies:
+  - commerce_authnet/form-accept
diff --git a/commerce_authnet.routing.yml b/commerce_authnet.routing.yml
new file mode 100644
index 0000000..e7c6589
--- /dev/null
+++ b/commerce_authnet.routing.yml
@@ -0,0 +1,7 @@
+commerce_authnet.cca_validation:
+  path: '/admin/commerce-authnet/cca-validation.json'
+  defaults:
+    _controller: '\Drupal\commerce_authnet\Controller\CcaValidation::validateJwt'
+    _title: 'CCA Validation'
+  requirements:
+    _access: 'TRUE'
diff --git a/composer.json b/composer.json
index efa84e3..702e118 100644
--- a/composer.json
+++ b/composer.json
@@ -12,6 +12,7 @@
     },
     "require": {
         "drupal/commerce": "~2.0",
-        "commerceguys/authnet": "^1.0.0-beta5"
+        "commerceguys/authnet": "^1.0.0-beta6",
+        "lcobucci/jwt": "~3.1"
     }
 }
diff --git a/js/commerce_authnet.accept.form.js b/js/commerce_authnet.accept.form.js
index 21e59de..aa8bbe9 100644
--- a/js/commerce_authnet.accept.form.js
+++ b/js/commerce_authnet.accept.form.js
@@ -14,8 +14,22 @@
     var last4 = '';
     // To be used to temporarily store month and year.
     var expiration = {};
+    var responseJwt = '';
 
     $form.find('.button--primary').prop('disabled', false);
+    
+    if (settings.ccaStatus == 1) {
+      if (settings.mode == 'test') {
+        Cardinal.configure({
+          logging: {
+            level: "on"
+          }
+        });
+    }
+      Cardinal.setup("init", {
+        jwt: $('.accept-js-data-cca-jwt-token').val()
+      });
+    }
 
     // Sends the card data to Authorize.Net and receive the payment nonce in
     // response.
@@ -25,7 +39,7 @@
       var cardData = {};
 
       // Extract the card number, expiration date, and card code.
-      cardData.cardNumber = $('#credit-card-number').val();
+      cardData.cardNumber = $('#credit-card-number').val().replace(/ /g, "");
       cardData.month = $('#expiration-month').val();
       cardData.year = $('#expiration-year').val();
       cardData.cardCode = $('#cvv').val();
@@ -39,9 +53,97 @@
       authData.apiLoginID = settings.apiLoginID;
       secureData.authData = authData;
 
-      // Pass the card number and expiration date to Accept.js for submission
-      // to Authorize.Net.
-      Accept.dispatchData(secureData, responseHandler);
+      if (settings.ccaStatus == 1) {
+        var order = {
+          OrderDetails: {
+            OrderNumber: settings.orderId,
+            Amount: settings.orderAmount,
+            CurrencyCode: settings.orderCurrency
+          },
+          Consumer: {
+            Account: {
+              AccountNumber: cardData.cardNumber,
+              ExpirationMonth: cardData.month,
+              ExpirationYear: "20" + cardData.year,
+              CardCode: cardData.cardCode,
+            }
+          }
+        };
+        Cardinal.start("cca", order);
+
+        Cardinal.on('payments.validated', function (data, jwt) {
+          try {
+            $.ajax({
+              method: 'post',
+              url: '/admin/commerce-authnet/cca-validation.json',
+              data: {
+                'responseJwt': jwt,
+                'gatewayId': settings.gatewayId
+              },
+              dataType: 'json'
+            }).done(function (responseData) {
+                if (responseData !== undefined && typeof responseData === 'object' && responseData.verified) {
+                  if ('ActionCode' in data) {
+                    switch (data.ActionCode) {
+                      case "SUCCESS":
+                      case "NOACTION":
+                        // Success indicates that we got back CCA values we can pass to the gateway
+                        // No action indicates that everything worked, but there is no CCA values to worry about, so we can move on with the transaction
+                        console.warn('The transaction was completed with no errors.', data.Payment.ExtendedData);
+
+                        responseJwt = jwt;
+                        // CCA Succesful, now complete the transaction with Authorize.Net
+                        Accept.dispatchData(secureData, responseHandler);
+                        break;
+
+                      case "FAILURE":
+                        // Failure indicates the authentication attempt failed
+                        console.warn('The authentication attempt failed.', data.Payment);
+                        alert('The authentication attempt failed.')
+                        location.reload();
+                        break;
+
+                      case "ERROR":
+                      default:
+                        // Error indicates that a problem was encountered at some point in the transaction
+                        console.warn('An issue occurred with the transaction.', data.Payment);
+                        alert('An issue occurred with the transaction.')
+                        location.reload();
+                        break;
+                    }
+                  }
+                  else {
+                    console.error("Failure while attempting to verify JWT signature: ", data);
+                    alert('Failure while attempting to verify JWT signature.');
+                    location.reload();
+                  }
+                }
+                else {
+                  console.error('Response data was incorrectly formatted: ', responseData);
+                  alert('Response data was incorrectly formatted.');
+                  location.reload();
+                }
+              })
+              .fail(function (xhr, ajaxError) {
+                console.log('Connection failure:', ajaxError);
+                alert('Connection failure.');
+                location.reload();
+              });
+
+          } catch (validateError) {
+            console.error('Failed while processing validate.', validateError);
+            alert('Failed while processing validate.');
+            location.reload();
+            
+          }
+        });
+
+      }
+      else {
+        // Pass the card number and expiration date to Accept.js for submission
+        // to Authorize.Net.
+        Accept.dispatchData(secureData, responseHandler);
+      }
     };
 
     // Process the response from Authorize.Net to retrieve the two elements of
@@ -65,6 +167,9 @@
       $('.accept-js-data-last4', $form).val(last4);
       $('.accept-js-data-month', $form).val(expiration.month);
       $('.accept-js-data-year', $form).val(expiration.year);
+      if (settings.ccaStatus == 1) {
+        $('.accept-js-data-cca-jwt-response-token', $form).val(responseJwt);
+      }
 
       // Clear out the values so they don't get posted to Drupal. They would
       // never be used, but for PCI compliance we should never send them at.
diff --git a/src/Controller/CcaValidation.php b/src/Controller/CcaValidation.php
new file mode 100644
index 0000000..a92143a
--- /dev/null
+++ b/src/Controller/CcaValidation.php
@@ -0,0 +1,65 @@
+<?php
+
+namespace Drupal\commerce_authnet\Controller;
+
+use Drupal\Core\DependencyInjection\ContainerInjectionInterface;
+use Symfony\Component\DependencyInjection\ContainerInterface;
+use Symfony\Component\HttpFoundation\RequestStack;
+use Lcobucci\JWT\Parser;
+use Lcobucci\JWT\Signer\Hmac\Sha256;
+use Drupal\commerce_payment\Entity\PaymentGateway;
+use Symfony\Component\HttpFoundation\JsonResponse;
+
+/**
+ * Verifies JWT in the CCA process.
+ *
+ * @see https://developer.cardinalcommerce.com/cardinal-cruise-activation.shtml#generatingServerJWTphp
+ */
+class CcaValidation implements ContainerInjectionInterface {
+
+  /**
+   * @var \Symfony\Component\HttpFoundation\RequestStack
+   */
+  private $requestStack;
+
+  /**
+   * Constructor.
+   *
+   * @param \Symfony\Component\HttpFoundation\RequestStack $request_stack
+   */
+  public function __construct(RequestStack $request_stack) {
+    $this->requestStack = $request_stack;
+  }
+
+  /**
+   * {@inheritdoc}
+   */
+  public static function create(ContainerInterface $container) {
+    return new static(
+      $container->get('request_stack')
+    );
+  }
+
+  /**
+   * Validates the JWT.
+   */
+  public function validateJwt() {
+    $response_jwt = $this->requestStack->getCurrentRequest()->request->get('responseJwt');
+
+    /** @var \Lcobucci\JWT\Token $token */
+    $token = (new Parser())->parse($response_jwt);
+    $signer = new Sha256();
+
+    $gateway_id = $this->requestStack->getCurrentRequest()->request->get('gatewayId');
+    /** @var \Drupal\commerce_payment\Entity\PaymentGateway $gateway */
+    $gateway = PaymentGateway::load($gateway_id);
+    $api_key = $gateway->getPlugin()->getCcaApiKey();
+    $claims = $token->getClaims();
+    $response = [
+      'verified' => $token->verify($signer, $api_key),
+      'payload' => $claims,
+    ];
+    return new JsonResponse($response);
+  }
+
+}
diff --git a/src/Plugin/Commerce/PaymentGateway/AcceptJs.php b/src/Plugin/Commerce/PaymentGateway/AcceptJs.php
index 590f5d9..d759cbd 100644
--- a/src/Plugin/Commerce/PaymentGateway/AcceptJs.php
+++ b/src/Plugin/Commerce/PaymentGateway/AcceptJs.php
@@ -23,6 +23,10 @@ use CommerceGuys\AuthNet\DataTypes\Profile;
 use CommerceGuys\AuthNet\DataTypes\TransactionRequest;
 use Drupal\commerce_payment\Plugin\Commerce\PaymentGateway\SupportsRefundsInterface;
 use CommerceGuys\AuthNet\DataTypes\ShipTo;
+use Drupal\Core\Form\FormStateInterface;
+use Lcobucci\JWT\Parser;
+use Lcobucci\JWT\Signer\Hmac\Sha256;
+use CommerceGuys\AuthNet\DataTypes\CardholderAuthentication;
 
 /**
  * Provides the Accept.js payment gateway.
@@ -45,12 +49,158 @@ class AcceptJs extends OnsiteBase implements SupportsRefundsInterface {
   /**
    * {@inheritdoc}
    */
+  public function buildConfigurationForm(array $form, FormStateInterface $form_state) {
+    $form = parent::buildConfigurationForm($form, $form_state);
+
+    $form['cca_status'] = [
+      '#type' => 'checkbox',
+      '#title' => $this->t('Enable Cardinal Cruise Authentication'),
+      '#default_value' => $this->configuration['cca_status'],
+    ];
+    $form['cca'] = [
+      '#type' => 'fieldset',
+      '#title' => $this->t('Cardinal Cruise Authentication'),
+      '#states' => [
+        'visible' => [
+          'input[name="configuration[authorizenet_acceptjs][cca_status]"]' => [
+            'checked' => TRUE,
+          ],
+        ],
+      ],
+    ];
+
+    $form['cca']['cca_api_id'] = [
+      '#type' => 'textfield',
+      '#title' => $this->t('API Identifier'),
+      '#default_value' => $this->configuration['cca_api_id'],
+      '#states' => [
+        'required' => [
+          'input[name="configuration[authorizenet_acceptjs][cca_status]"]' => [
+            'checked' => TRUE,
+          ],
+        ],
+      ],
+    ];
+
+    $form['cca']['cca_org_unit_id'] = [
+      '#type' => 'textfield',
+      '#title' => $this->t('Org Unit ID'),
+      '#default_value' => $this->configuration['cca_org_unit_id'],
+      '#states' => [
+        'required' => [
+          'input[name="configuration[authorizenet_acceptjs][cca_status]"]' => [
+            'checked' => TRUE,
+          ],
+        ],
+      ],
+    ];
+
+    $form['cca']['cca_api_key'] = [
+      '#type' => 'textfield',
+      '#title' => $this->t('API key'),
+      '#default_value' => $this->configuration['cca_api_key'],
+      '#states' => [
+        'required' => [
+          'input[name="configuration[authorizenet_acceptjs][cca_status]"]' => [
+            'checked' => TRUE,
+          ],
+        ],
+      ],
+    ];
+
+    return $form;
+  }
+
+  /**
+   * {@inheritdoc}
+   */
+  public function submitConfigurationForm(array &$form, FormStateInterface $form_state) {
+    parent::submitConfigurationForm($form, $form_state);
+
+    if (!$form_state->getErrors()) {
+      $values = $form_state->getValue($form['#parents']);
+      $this->configuration['cca_status'] = $values['cca_status'];
+      $this->configuration['cca_api_id'] = $values['cca']['cca_api_id'];
+      $this->configuration['cca_org_unit_id'] = $values['cca']['cca_org_unit_id'];
+      $this->configuration['cca_api_key'] = $values['cca']['cca_api_key'];
+    }
+  }
+
+  /**
+   * Get the CCA API Identifier.
+   *
+   * @return string
+   */
+  public function getCcaApiId() {
+    if ($this->configuration['cca_status']) {
+      // Test API Id.
+      // @see https://developer.cardinalcommerce.com/try-it-now.shtml
+      if ($this->configuration['mode'] == 'test') {
+        return '582e0a2033fadd1260f990f6';
+      }
+      else {
+        return $this->configuration['cca_api_id'];
+      }
+    }
+  }
+
+  /**
+   * Get the CCA API Identifier.
+   *
+   * @return string
+   */
+  public function getCcaOrgUnitId() {
+    if ($this->configuration['cca_status']) {
+      // Test Org Unit ID.
+      // @see https://developer.cardinalcommerce.com/try-it-now.shtml
+      if ($this->configuration['mode'] == 'test') {
+        return '582be9deda52932a946c45c4';
+      }
+      else {
+        return $this->configuration['cca_org_unit_id'];
+      }
+    }
+  }
+
+  /**
+   * Get the CCA API Key.
+   *
+   * @return string
+   */
+  public function getCcaApiKey() {
+    if ($this->configuration['cca_status']) {
+      // Test API Key.
+      // @see https://developer.cardinalcommerce.com/try-it-now.shtml
+      if ($this->configuration['mode'] == 'test') {
+        return '754be3dc-10b7-471f-af31-f20ce12b9ec1';
+      }
+      else {
+        return $this->configuration['cca_api_key'];
+      }
+    }
+  }
+
+  /**
+   * {@inheritDoc}
+   */
+  public function getJsLibrary() {
+    if ($this->configuration['cca_status']) {
+      if ($this->getMode() === 'test') {
+        return 'commerce_authnet/cardinalcruise-dev';
+      }
+      return 'commerce_authnet/cardinalcruise';
+    }
+    return 'commerce_authnet/form-accept';
+  }
+
+  /**
+   * {@inheritdoc}
+   */
   public function createPayment(PaymentInterface $payment, $capture = TRUE) {
     $this->assertPaymentState($payment, ['new']);
     $payment_method = $payment->getPaymentMethod();
     $this->assertPaymentMethod($payment_method);
 
-
     $order = $payment->getOrder();
     $owner = $payment_method->getOwner();
 
@@ -60,6 +210,26 @@ class AcceptJs extends OnsiteBase implements SupportsRefundsInterface {
       'amount' => $payment->getAmount()->getNumber(),
     ]);
 
+    if (isset($_SESSION['commerce_authnet'][$payment_method->id()])) {
+      // Do not send ECI and CAVV values when reusing a payment method.
+      $payment_method_has_been_used = $this->entityQueryService->get('commerce_payment')
+        ->condition('payment_method', $payment_method->id())
+        ->execute();
+      if (!$payment_method_has_been_used) {
+        $cardholder_authentication = new CardholderAuthentication([
+          'authenticationIndicator' => $_SESSION['commerce_authnet'][$payment_method->id()]['eci'],
+          // This is quite undocumented, but seems that cavv needs to be
+          // urlencoded.
+          // @see https://community.developer.authorize.net/t5/Integration-and-Testing/Cardholder-Authentication-extraOptions-invalid-error/td-p/57955
+          'cardholderAuthenticationValue' => urlencode($_SESSION['commerce_authnet'][$payment_method->id()]['cavv']),
+        ]);
+        $transaction_request->addDataType($cardholder_authentication);
+      }
+      else {
+        unset($_SESSION['commerce_authnet'][$payment_method->id()]);
+      }
+    }
+
     // @todo update SDK to support data type like this.
     // Initializing the profile to charge and adding it to the transaction.
     $customer_profile_id = $this->getRemoteCustomerId($owner);
@@ -128,6 +298,10 @@ class AcceptJs extends OnsiteBase implements SupportsRefundsInterface {
           $payment_method->delete();
           throw new PaymentGatewayException('The provided payment method is no longer valid');
 
+        case 'E00042':
+          $payment_method->delete();
+          throw new PaymentGatewayException('You cannot add more than 10 payment methods.');
+
         default:
           throw new PaymentGatewayException($message->getText());
       }
@@ -199,6 +373,27 @@ class AcceptJs extends OnsiteBase implements SupportsRefundsInterface {
    * @todo Needs kernel test
    */
   public function createPaymentMethod(PaymentMethodInterface $payment_method, array $payment_details) {
+    // We don't want 3DS on the user payment method form.
+    if (!empty($this->getConfiguration()['cca_status']) && !empty($payment_details['cca_jwt_token'])) {
+      if (empty($payment_details['cca_jwt_response_token'])) {
+        throw new PaymentGatewayException('Cannot continue when CCA is enabled but not used.');
+      }
+
+      /** @var \Lcobucci\JWT\Token $token */
+      $token = (new Parser())->parse($payment_details['cca_jwt_response_token']);
+      $signer = new Sha256();
+
+      if (!$token->verify($signer, $this->getCcaApiKey())) {
+        throw new PaymentGatewayException('Response CCA JWT is not valid.');
+      }
+      $claims = $token->getClaims();
+      /** @var \Lcobucci\JWT\Claim $payload */
+      $payload = $claims['Payload'];
+      if (isset($payload->getValue()->Payment->ExtendedData->SignatureVerification) && $payload->getValue()->Payment->ExtendedData->SignatureVerification === 'N') {
+        throw new PaymentGatewayException('Unsuccessful signature verification.');
+      }
+    }
+
     $required_keys = [
       'data_descriptor', 'data_value',
     ];
@@ -217,6 +412,17 @@ class AcceptJs extends OnsiteBase implements SupportsRefundsInterface {
     $payment_method->setExpiresTime($expires);
 
     $payment_method->save();
+    if (!empty($this->getConfiguration()['cca_status']) && !empty($payment_details['cca_jwt_token'])) {
+      // We might not have a CAVV value.
+      // @see https://usa.visa.com/dam/VCOM/download/merchants/verified-by-visa-acquirer-merchant-implementation-guide.pdf
+      // Table 5-2.
+      if (isset($payload->getValue()->Payment->ExtendedData->CAVV)) {
+        $_SESSION['commerce_authnet'][$payment_method->id()]['cavv'] = $payload->getValue()->Payment->ExtendedData->CAVV;
+      }
+      if (isset($payload->getValue()->Payment->ExtendedData->ECIFlag)) {
+        $_SESSION['commerce_authnet'][$payment_method->id()]['eci'] = $payload->getValue()->Payment->ExtendedData->ECIFlag;
+      }
+    }
   }
 
   /**
diff --git a/src/Plugin/Commerce/PaymentGateway/OnsiteBase.php b/src/Plugin/Commerce/PaymentGateway/OnsiteBase.php
index 41c5a72..fb6ea34 100644
--- a/src/Plugin/Commerce/PaymentGateway/OnsiteBase.php
+++ b/src/Plugin/Commerce/PaymentGateway/OnsiteBase.php
@@ -28,6 +28,7 @@ use Symfony\Component\DependencyInjection\ContainerInterface;
 use Drupal\commerce_payment\Plugin\Commerce\PaymentGateway\OnsitePaymentGatewayInterface;
 use Drupal\commerce_payment\Plugin\Commerce\PaymentGateway\SupportsAuthorizationsInterface;
 use CommerceGuys\AuthNet\DataTypes\Tax;
+use Drupal\Core\Entity\Query\QueryFactory;
 
 /**
  * Provides the Authorize.net payment gateway base class.
@@ -56,9 +57,16 @@ abstract class OnsiteBase extends OnsitePaymentGatewayBase implements  OnsitePay
   protected $logger;
 
   /**
+   * The entity field query service.
+   *
+   * @var \Drupal\Core\Entity\Query\QueryFactory
+   */
+  protected $entityQueryService;
+
+  /**
    * {@inheritdoc}
    */
-  public function __construct(array $configuration, $plugin_id, $plugin_definition, EntityTypeManagerInterface $entity_type_manager, PaymentTypeManager $payment_type_manager, PaymentMethodTypeManager $payment_method_type_manager, TimeInterface $time, ClientInterface $client, LoggerInterface $logger) {
+  public function __construct(array $configuration, $plugin_id, $plugin_definition, EntityTypeManagerInterface $entity_type_manager, PaymentTypeManager $payment_type_manager, PaymentMethodTypeManager $payment_method_type_manager, TimeInterface $time, ClientInterface $client, LoggerInterface $logger, QueryFactory $entity_query_service) {
     parent::__construct($configuration, $plugin_id, $plugin_definition, $entity_type_manager, $payment_type_manager, $payment_method_type_manager, $time);
 
     $this->httpClient = $client;
@@ -69,6 +77,7 @@ abstract class OnsiteBase extends OnsitePaymentGatewayBase implements  OnsitePay
       'transaction_key' => $this->configuration['transaction_key'],
       'client_key' => $this->configuration['client_key'],
     ]);
+    $this->entityQueryService = $entity_query_service;
   }
 
   /**
@@ -84,7 +93,8 @@ abstract class OnsiteBase extends OnsitePaymentGatewayBase implements  OnsitePay
       $container->get('plugin.manager.commerce_payment_method_type'),
       $container->get('datetime.time'),
       $container->get('http_client'),
-      $container->get('commerce_authnet.logger')
+      $container->get('commerce_authnet.logger'),
+      $container->get('entity.query')
     );
   }
 
diff --git a/src/PluginForm/AcceptJsAddForm.php b/src/PluginForm/AcceptJsAddForm.php
index cb43dc5..9c5211d 100644
--- a/src/PluginForm/AcceptJsAddForm.php
+++ b/src/PluginForm/AcceptJsAddForm.php
@@ -4,7 +4,8 @@ namespace Drupal\commerce_authnet\PluginForm;
 
 use Drupal\commerce_payment\PluginForm\PaymentMethodAddForm as BasePaymentMethodAddForm;
 use Drupal\Core\Form\FormStateInterface;
-use Drupal\commerce_authnet\Plugin\Commerce\PaymentMethodType\AuthorizeNetEcheck;
+use Lcobucci\JWT\Builder;
+use Lcobucci\JWT\Signer\Hmac\Sha256;
 
 class AcceptJsAddForm extends BasePaymentMethodAddForm {
 
@@ -14,7 +15,7 @@ class AcceptJsAddForm extends BasePaymentMethodAddForm {
   public function buildCreditCardForm(array $element, FormStateInterface $form_state) {
     // Alter the form with AuthorizeNet Accept JS specific needs.
     $element['#attributes']['class'][] = 'authorize-net-accept-js-form';
-    /** @var \Drupal\commerce_authnet\Plugin\Commerce\PaymentGateway\AuthorizeNetBase $plugin */
+    /** @var \Drupal\commerce_authnet\Plugin\Commerce\PaymentGateway\AcceptJs $plugin */
     $plugin = $this->plugin;
 
     if ($plugin->getMode() == 'test') {
@@ -23,11 +24,13 @@ class AcceptJsAddForm extends BasePaymentMethodAddForm {
     else {
       $element['#attached']['library'][] = 'commerce_authnet/accept-js-production';
     }
-    $element['#attached']['library'][] = 'commerce_authnet/form-accept';
     $element['#attached']['drupalSettings']['commerceAuthorizeNet'] = [
       'clientKey' => $plugin->getConfiguration()['client_key'],
       'apiLoginID' => $plugin->getConfiguration()['api_login'],
       'paymentMethodType' => 'credit_card',
+      'ccaStatus' => 0,
+      'mode' => $plugin->getMode(),
+      'gatewayId' => $this->getEntity()->getPaymentGatewayId(),
     ];
 
     // Fields placeholder to be built by the JS.
@@ -164,6 +167,28 @@ class AcceptJsAddForm extends BasePaymentMethodAddForm {
         'class' => ['accept-js-data-year'],
       ],
     ];
+    /** @var \Drupal\commerce_order\Entity\Order $order */
+    if ($order = $this->routeMatch->getParameter('commerce_order')) {
+      if ($plugin->getConfiguration()['cca_status']) {
+        $element['cca_jwt_token'] = [
+          '#type' => 'hidden',
+          '#attributes' => [
+            'class' => ['accept-js-data-cca-jwt-token'],
+          ],
+          '#value' => (string) $this->generateJwt(),
+        ];
+        $element['cca_jwt_response_token'] = [
+          '#type' => 'hidden',
+          '#attributes' => [
+            'class' => ['accept-js-data-cca-jwt-response-token'],
+          ],
+        ];
+        $element['#attached']['drupalSettings']['commerceAuthorizeNet']['orderId'] = $order->id();
+        $element['#attached']['drupalSettings']['commerceAuthorizeNet']['orderAmount'] = round($order->getTotalPrice()->getNumber());
+        $element['#attached']['drupalSettings']['commerceAuthorizeNet']['orderCurrency'] = $order->getTotalPrice()->getCurrencyCode();
+        $element['#attached']['drupalSettings']['commerceAuthorizeNet']['ccaStatus'] = 1;
+      }
+    }
 
     return $element;
   }
@@ -189,4 +214,37 @@ class AcceptJsAddForm extends BasePaymentMethodAddForm {
     }
   }
 
+  /**
+   * Create JWT token for CCA.
+   *
+   * @return \Lcobucci\JWT\Token
+   */
+  protected function generateJwt(){
+    $current_time = time();
+    $expire_time = 3600;
+    /** @var \Drupal\commerce_order\Entity\Order $order */
+    if ($order = $this->routeMatch->getParameter('commerce_order')) {
+      $order_details = [
+        'OrderDetails' => [
+          'OrderNumber' => $order->getOrderNumber(),
+        ],
+      ];
+    }
+
+    /** @var \Drupal\commerce_authnet\Plugin\Commerce\PaymentGateway\AcceptJs $plugin */
+    $plugin = $this->plugin;
+
+    $token = (new Builder())->setIssuer($plugin->getCcaApiId())
+      ->setId(uniqid(), TRUE)
+      ->setIssuedAt($current_time)
+      ->setExpiration($current_time + $expire_time)
+      ->set('OrgUnitId', $plugin->getCcaOrgUnitId())
+      ->set('Payload', $order_details)
+      ->set('ObjectifyPayload', TRUE)
+      ->sign(new Sha256(), $plugin->getCcaApiKey())
+      ->getToken();
+
+    return $token;
+  }
+
 }
