npm package: @gr4vy/secure-fields
Description: Gr4vy-hosted secure fields offering advanced theming, PCI compliance, event handling, and more.
Author: Gr4vy
Latest version: 2.3.1

# Secure Fields

![NPM Version](https://img.shields.io/npm/v/@gr4vy/secure-fields?color=green)
[![GitHub license](https://img.shields.io/github/license/Naereen/StrapDown.js.svg)](https://github.com/gr4vy/secure-fields/blob/main/LICENSE)
[![Changelog](https://img.shields.io/badge/changelog-dimgrey?logo=npm&logoColor=white)](https://www.runpkg.com/?@gr4vy/secure-fields/CHANGELOG.md)

Add Secure Fields to your Node app.

Use [`@gr4vy/secure-fields-react`](../secure-fields-react) in a React application or [`@gr4vy/secure-fields-cdn`](../secure-fields-cdn) in non-Node web application.

## Usage

Via the command line, install this package as follows.

```bash
npm install @gr4vy/secure-fields --save-prod
# yarn add @gr4vy/secure-fields --save
```

## Get started

To use Secure Fields, you need some placeholder elements to attach the secure fields on to. Each of these elements will be replaced by a secure field. These elements can be `<input>` but do not need to be.

```html
<label for="cc-number">Card Number</label>
<input id="cc-number" />

<label for="cc-cvv">Security code</label>
<input id="cc-cvv" />

<label for="cc-expiry">Expiry date</label>
<input id="cc-expiry" />

<button id="cc-button">Submit</button>
```

To use Secure Fields, call the `new SecureFields()` method with a configuration object that includes the `environment` (`sandbox` or `production`), your `gr4vyId` and a `sessionId` obtained from calling the [Checkout Sessions API](https://gr4vy.com/docs/reference#tag/Checkout-Sessions). An optional `paymentMethod` object with `id` and `scheme` can also be passed to use Secure Fields with a stored payment method.

Then, add the fields and event listeners needed to handle the form submission.

```js
const { SecureFields } = require('@gr4vy/secure-fields')

// Alternatively
// import { SecureFields } from '@gr4vy/secure-fields'

const secureFields = new SecureFields({
  gr4vyId: '[GR4VY_ID]',
  environment: 'sandbox',
  sessionId: '[SESSION_ID]',

  // For stored payment methods (optional):
  // paymentMethod: {
  //   id: '[PAYMENT_METHOD_ID]',
  //   scheme: 'visa' // Enables accurate CVV validation (3 digits for Visa/Mastercard, 4 for Amex)
  // },

  // Deprecated:
  // paymentMethodId: '[PAYMENT_METHOD_ID]', // uuid of a stored payment method
})

secureFields.addFont('Lato')

const styles = {
  color: 'black',
  fontSize: '18px',
  fontFamily: 'Lato',
  ':focus': {
    color: 'blue',
  },
}

const number = secureFields.addCardNumberField('#cc-number', { styles })
const expiry = secureFields.addExpiryDateField('#cc-expiry', { styles })
const cvv = secureFields.addSecurityCodeField('#cc-cvv', { styles })

secureFields.addEventListener(SecureFields.Events.CARD_VAULT_SUCCESS, () =>
  console.log('Card tokenized successfully')
)

secureFields.addEventListener(
  SecureFields.Events.CARD_VAULT_FAILURE,
  (data) => console.log('Card tokenization failed', data) // data.status, data.code, data.message
)

number.addEventListener('input', (data) => {
  console.warn('Input changed', data) // data.schema, data.codeLabel...
})

const button = document.querySelector('#cc-button')
button.addEventListener('click', () => {
  secureFields.submit()
})
```

> **Note**: Replace `[GR4VY_ID]` with your Gr4vy ID and `[SESSION_ID]` with a valid checkout session id.

This will initialize Secure Fields and replace each of the inputs with a corresponding secure element. On submit, it will store the card data securely with Gr4vy, after which you can create a transaction or vault the card for later use.

You can also collect other kind of information along with the card data. We currently support an additional postal code field, which can be added to your form using the `addField` method, passing the specific `type` and the rest of the options.

```html
<!-- placeholder HTML code -->
<label for="postal-code">Postal code</label>
<input id="postal-code" />
```

```js
// js code
const postalCode = secureFields.addField('#postal-code', {
  type: 'postalCode',
  pattern: '[A-Z][0-9]\\s[0-9][A-Z]{2}' // optional, defaults to 5 characters minimum
  styles,
  ...
})

postalCode.addEventListener('input', (data) => {
  console.warn('Input changed', data)
})
```

Each field instance exposes a `clear()` method to reset the value programmatically.

```js
const number = secureFields.addCardNumberField('#cc-number', { styles })
number.clear()
```

For more information please
refer to the [Secure Fields get started guide](https://docs.gr4vy.com/guides/payments/secure-fields/quick-start/overview).

## Styles

The outer styling of every Secure Field is completely in your control by applying your own CSS to the following class names.

```css
/* Applied to each field */
.secure-fields__input {
}
/* Applied to the card number field */
.secure-fields__input--number {
}
/* Applied to the expiry date field */
.secure-fields__input--expiry-date {
}
/* Applied to the security code field */
.secure-fields__input--security-code {
}
/* Applied to the postal code field */
.secure-fields__input--postal-code {
}
/* Applied to a focused field */
.secure-fields__input[data-secure-fields-focused] {
}
/* Applied to an invalid field */
.secure-fields__input[data-secure-fields-invalid] {
}
/* Applied to an autofilled field */
.secure-fields__input[data-secure-fields-autofilled] {
}
```

To set the CSS of the content of a field an object of CSS rules can be passed to the `addCardNumberField`, `addExpiryDateField`, `addSecurityCodeField` and `addField` methods.

```js
const styles = {
  // Default styles applied to field
  color: "#66666",
  fontSize: "1.3em",
  // ...etc

  // Applied when field has a value autofilled by browser/extension
  ':autofill': { ... },
  // Applied when field is hovered
  ':hover': { ... },
  // Applied when field is focused
  ':focus': { ... },
  // Applied when field is disabled
  ':disabled': { ... },
  // Applied when field is valid
  ':valid': { ... },
  // Applied when field is invalid
  ':invalid': { ... },
  // Applied to field placeholder
  '::placeholder': { ... },
}
```

Not all CSS properties can be set. The currently supported list is as follows.

```
backgroundColor
boxShadow
caretColor
color
colorScheme
cursor
font
fontFamily
fontFeatureSettings
fontKerning
fontSize
fontSizeAdjust
fontStretch
fontStyle
fontVariant
fontVariantAlternates
fontVariantCaps
fontVariantEastAsian
fontVariantLigatures
fontVariantNumeric
fontVariationSettings
fontWeight
letterSpacing
lineHeight
opacity
padding
textAlign
textShadow
textRendering
transition
MozOsxFontSmoothing
WebkitFontSmoothing
```

## Events

### Global events

The following events can be listened to by attaching an event handler to the `SecureFields` instance using the `addEventListener` method.

| Name                 | Description                                                                                                                                                                 | Example                                                                                                                                                                           |
| -------------------- | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `CARD_VAULT_SUCCESS` | Triggered when the card is successfully vaulted.                                                                                                                            | `secureFields.addEventListener(SecureFields.Events.CARD_VAULT_SUCCESS, () => { console.log('Card has been tokenized successfully!') })`                                           |
| `CARD_VAULT_FAILURE` | Triggered when the card vaulting fails.                                                                                                                                     | `secureFields.addEventListener(SecureFields.Events.CARD_VAULT_FAILURE, ({ code, status, message }) => { console.log('Couldn\'t tokenize the card', { code, status, message }) })` |
| `FORM_CHANGE`        | Triggered when one of the form field is changed. The `complete` property shows if the form is ready to be submitted, i.e. card number and expiry date are filled and valid. | `secureFields.addEventListener(SecureFields.Events.FORM_CHANGE, ({ complete, fields }) => { console.log('Form state', { complete, fields }) })`                                   |
| `READY`              | Triggered when Secure Fields is loaded and ready to be used.                                                                                                                | `secureFields.addEventListener(SecureFields.READY, () => { console.log('Secure fields loaded') })`                                                                                |

### Field events

The following events can be listened to by attaching an event handler to a field (returned by the `addCardNumberField`, `addExpiryDateField`, `addSecurityCodeField` and `addField` methods) using the `addEventListener` method.

Some of these provide additional useful data like the card BIN, validation status, and scheme. For example, the input event on a card number field might include `{ schema: 'visa', codeLabel: 'CVV', valid: true, ... }`.

| Name    | Description                                      | Example                                                                                                                                                                                        |
| ------- | ------------------------------------------------ | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `blur`  | Triggered when the field loses focus.            | `cardNumberField.addEventListener('blur', (data) => { console.log(data) /* { id: 'number' } */ })`                                                                                             |
| `focus` | Triggered when the field gains focus.            | `cardNumberField.addEventListener('focus', (data) => { console.log(data) /* { id: 'number' } */ })`                                                                                            |
| `input` | Triggered when the field value has been changed. | `cardNumberField.addEventListener('input', (data) => { console.log(data) /* { id: 'number', schema: 'visa', codeLabel: 'CVV', valid: true, empty: true, autofilled: false, bin: '411111' } */` |

## Click to Pay

Click to Pay is the better way to pay online – featuring advanced payment technology built on secure remote commerce industry standards.

### Prerequisites

Follow the instructions for [Click to Pay Merchant Setup](https://docs.gr4vy.com/guides/payments/secure-fields/click-to-pay#merchant-setup).

### Adding Click to Pay

Once Secure Fields is configured, you can start adding Click to Pay to your checkout.

Firstly, add a placeholder component to your form so Secure Fields knows where to render the Click to Pay component.

Then, add a simple sign-in form to let users access their Click to Pay stored cards.

Additionally, add a checkbox to allow a customer not already enrolled to determine if they want to share the card data with Click to Pay or not.

Finally, ensure card inputs are wrapped with a container element (e.g. `<form />`) with a specific id.

```html
<div id="click-to-pay"></div>

<div id="click-to-pay-sign-in" style="display: none;">
  <label>Access your Click to Pay stored cards</label>
  <input type="text" id="phoneOrEmail" />
  <button id="signInButton">Continue</button>
</div>

<form id="card-form" style="display: none;">
  <label htmlFor="cc-number">Card number</label>
  <input type="text" id="cc-number" />

  <label htmlFor="cc-expiry-date">Expiry date</label>
  <input type="text" id="cc-expiry-date" />

  <label htmlFor="cc-security-code">Security code</label>
  <input type="text" id="cc-security-code" />
</form>

<input type="checkbox" id="click-to-pay-consent-checkbox" />
<label for="click-to-pay-consent-checkbox"
  >Store my card with Click to Pay</label
>

<script>
  var phoneOrEmail = document.querySelector('#phoneOrEmail')
  var signInButton = document.querySelector('#signInButton')
  signInButton.addEventListener('click', function () {
    clickToPay.signIn({ email: phoneOrEmail.value })
  })
</script>
```

Next, attach the secure field for Click to Pay to this element. This will require the email and/or phone number of the user you want to create a transaction for. It also requires an HTML query for the consent checkbox that controls if the card data for a new card is shared with Click to Pay or not.

```js
const clickToPay = secureFields.addClickToPay('#click-to-pay', {
  dpaLocale: 'en_AU',
  cardBrands: ['mastercard', 'visa', 'american-express'],
  email: 'john@example.com',
  mobileNumber: {
    countryCode: '61',
    phoneNumber: '491570159',
  },
  consentCheckbox: '#click-to-pay-consent-checkbox',
  signIn: '#click-to-pay-sign-in',
  cardForm: '#card-form',
})
// clickToPay = { element: <div id="click-to-pay" />, signIn: ..., options: { dpaName: ... } }
```

The available Click to Pay options are the following:

| Option Name       | Description                                                                                                                                                                                                                                                                                           |
| ----------------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `srcDpaId`        | DPA Identifier. This is a unique identifier for you Digital Payment Application (DPA), which was generated during onboarding.                                                                                                                                                                         |
| `dpaName`         | Legal name of registered DPA.                                                                                                                                                                                                                                                                         |
| `cardBrands`      | List of card schemes the merchant accepts. We currently support `mastercard`, `maestro`, `visa`, `amex`, `discover`                                                                                                                                                                                   |
| `cardForm`        | A reference to the card form wrapper.                                                                                                                                                                                                                                                                 |
| `signIn`          | A reference to the sign-in elements wrapper.                                                                                                                                                                                                                                                          |
| `consentCheckbox` | A reference to the opt-in consent checkbox element.                                                                                                                                                                                                                                                   |
| `learnMoreLink`   | A reference to the learn more link element.                                                                                                                                                                                                                                                           |
| `email`           | The user email used to access Click to Pay.                                                                                                                                                                                                                                                           |
| `mobileNumber`    | The user phone number used to access Click to Pay. Required format is `{ countryCode: string, phoneNumber: string }`                                                                                                                                                                                  |
| `dynamicDataType` | The type of cryptogram or token used for the card data. See the [Mastercard docs](https://developer.mastercard.com/unified-checkout-solutions/documentation/sdk-reference/parameters/#payment-options) for more information. Possible values are `NONE` and `CARD_APPLICATION_CRYPTOGRAM_SHORT_FORM`. |

### Additional Global events

The following Click to Pay events can be listened to by attaching an event handler to the `SecureFields` instance using the `addEventListener` method.

| Name                                       | Description                                                                                     | Example                                                                                                                                                                                                                                                                         |
| ------------------------------------------ | ----------------------------------------------------------------------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `CLICK_TO_PAY_INITIALIZED`                 | Triggered when Click to Pay has been initialized.                                               | `secureFields.addEventListener(SecureFields.Events.CLICK_TO_PAY_INITIALIZED, (clickToPay) => { console.log('Click to Pay initialized', clickToPay) })`                                                                                                                          |
| `CLICK_TO_PAY_READY`                       | Triggered when Click to Pay is ready.                                                           | `secureFields.addEventListener(SecureFields.Events.CLICK_TO_PAY_READY, ({ buyerExists }) => { console.log('Click to Pay ready', { buyerExists }) })`                                                                                                                            |
| `CLICK_TO_PAY_SIGN_OUT`                    | Triggered when a user signs out of Click to Pay.                                                | `secureFields.addEventListener(SecureFields.Events.CLICK_TO_PAY_SIGN_OUT, ({ buyerExists }) => { console.log('User signed out') })`                                                                                                                                             |
| `CLICK_TO_PAY_ERROR`                       | Triggered when Click to Pay throws an error.                                                    | `secureFields.addEventListener(SecureFields.Events.CLICK_TO_PAY_ERROR, (error) => { console.log('Click to Pay error', error) }) // "RETRIES_EXCEEDED" \| "CODE_INVALID" \| "INVALID_CARD" \| "SIGN_OUT_FAILED" \| "ACCT_INACCESSIBLE" \| "UNKNOWN" \| "USER_NOT_RECOGNIZED" \|` |
| `CLICK_TO_PAY_CANCEL`                      | Triggered when a user closes / cancels Click to Pay.                                            | `secureFields.addEventListener(SecureFields.Events.CLICK_TO_PAY_CANCEL, () => { console.log('User cancelled Click to Pay') })`                                                                                                                                                  |
| `CLICK_TO_PAY_CHECKOUT_WITH_NEW_CARD`      | Triggered when a user performs the checkout with a new card (not yet enrolled in Click to Pay). | `secureFields.addEventListener(SecureFields.Events.CLICK_TO_PAY_CHECKOUT_WITH_NEW_CARD, () => { console.log('User is using a new card') })`                                                                                                                                     |
| `CLICK_TO_PAY_UNABLE_TO_LOAD_DPA`          | Triggered when the provided Click to Pay DPA cannot be loaded.                                  | `secureFields.addEventListener(SecureFields.Events.CLICK_TO_PAY_UNABLE_TO_LOAD_DPA, () => { console.log('Unable to load Click to Pay DPA') })`                                                                                                                                  |
| `CLICK_TO_PAY_VISIBILITY_CHANGE`           | Triggered when the Click to Pay element is shown or hidden.                                     | `secureFields.addEventListener(SecureFields.Events.CLICK_TO_PAY_VISIBILITY_CHANGE, (visible) => { console.log('Click to Pay element is ' + visible ? "visible" : "not visible") })`                                                                                             |
| `CLICK_TO_PAY_CARD_FORM_VISIBILITY_CHANGE` | Triggered when the card form container is shown or hidden.                                      | `secureFields.addEventListener(SecureFields.Events.CLICK_TO_PAY_CARD_FORM_VISIBILITY_CHANGE, (visible) => { console.log('Card form is ' + visible ? "visible" : "not visible") })`                                                                                              |
| `CLICK_TO_PAY_SIGN_IN_VISIBILITY_CHANGE`   | Triggered when the sign in container is shown or hidden.                                        | `secureFields.addEventListener(SecureFields.Events.CLICK_TO_PAY_SIGN_IN_VISIBILITY_CHANGE, (visible) => { console.log('Sign in is ' + visible ? "visible" : "not visible") })`                                                                                                  |
| `METHOD_CHANGE`                            | Triggered when the user selects a different method (either `card` or `click-to-pay`)            | `secureFields.addEventListener(SecureFields.Events.METHOD_CHANGE, (method) => { console.log('Selected method changed', method) })`                                                                                                                                              |

## API reference

### Getters

| Name      | Description                                                                     |
| --------- | ------------------------------------------------------------------------------- |
| `Events`  | Gives access to the supported events. <br /><br />`SecureFields.Events.READY`   |
| `version` | Returns the current version of the instance. <br /><br />`SecureFields.version` |

### Methods

| Name                   | Description                                                                                                                                                                                                                                                                                                                                    |
| ---------------------- | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `constructor`          | Instantiates SecureFields with a configuration object include `environment`, `gr4vyId` and a session id. An optional `paymentMethod` object with `id` and `scheme` can also be passed to use Secure Fields with a stored payment method. <br /><br />`new SecureFields({...})`                                                                 |
| `addCardNumberField`   | Injects a secure field of type `number`. <br /><br />`secureFields.addCardNumberField('#cc-number', { placeholder: 'Enter card number', ... })`                                                                                                                                                                                                |
| `addSecurityCodeField` | Injects a secure field of type `securityCode`. <br /><br />`secureFields.addSecurityCodeField('#cc-security-code', { placeholder: 'Enter security code', ... })`                                                                                                                                                                               |
| `addExpiryDateField`   | Injects a secure field of type `expiryDate`. <br /><br />`secureFields.addExpiryDateField('#cc-expiry-date', { placeholder: 'Enter expiry date', ... })`                                                                                                                                                                                       |
| `addField`             | Allows to inject secure fields based on `type`, for example a postal code field. <br /><br />`secureFields.addField('#postal-code', { type: 'postalCode', placeholder: 'Enter postal code', ... })`                                                                                                                                            |
| `addClickToPay`        | Injects a field that initializes Click to Pay. <br /><br />`secureFields.addClickToPay('#click-to-pay', { dpaLocale: 'en_AU', cardBrands: ['mastercard', 'visa'], ... })`                                                                                                                                                                      |
| `addEventListener`     | Attaches an event handler to the SecureFields instance or to a secure field in order to listen to specific events. Requires one of the events supported and a callback. <br /><br />`secureFields.addEventListener(SecureFields.Events.READY, (data) => { ... })` <br /><br />`cardNumberField.addEventListener('input', (data) => { ... })`   |
| `removeEventListener`  | Removes a previously attached event handler.                                                                                                                                                                                                                                                                                                   |
| `submit`               | Calls the Vault API to tokenize and store the card data. <br /><br />`secureFields.submit()`                                                                                                                                                                                                                                                   |
| `setDebug`             | Enable / disable debug mode. When the debug mode is enabled, SecureFields logs information to the console. <br /><br />`secureFields.setDebug(true)`                                                                                                                                                                                           |
| `addFont`              | Load a custom font from [Google Fonts](https://fonts.google.com/) to be used inside inputs. You can define the font family as well as styles or weights as a string (e.g. "Lato:400,600"). To use the loaded font, add the correct `fontFamily` property to the styles object when creating fields. <br /><br />`secureFields.addFont('Lato')` |