skyflow-js
Skyflow’s JavaScript SDK can be used to securely collect, tokenize, and reveal sensitive data in the browser without exposing your front-end infrastructure to sensitive data.
Table of Contents
Including Skyflow.js
Using script tag
<script src="https://js.skyflow.com/v1/index.js"></script>
Using npm
npm install skyflow-js
Initializing Skyflow.js
Use the init()
method to initialize a Skyflow client as shown below.
import Skyflow from 'skyflow-js'
const skyflowClient = Skyflow.init({
vaultID: 'string',
vaultURL: 'string',
getBearerToken: helperFunc,
options: {
logLevel: Skyflow.LogLevel,
env: Skyflow.Env
}
});
For the getBearerToken
parameter, pass in a helper function that retrieves a Skyflow bearer token from your backend. This function will be invoked when the SDK needs to insert or retrieve data from the vault. A sample implementation is shown below:
For example, if the response of the consumer tokenAPI is in the below format
{
"accessToken": string,
"tokenType": string
}
then, your getBearerToken Implementation should be as below
const getBearerToken = () => {
return new Promise((resolve, reject) => {
const Http = new XMLHttpRequest();
Http.onreadystatechange = () => {
if (Http.readyState === 4) {
if (Http.status === 200) {
const response = JSON.parse(Http.responseText);
resolve(response.accessToken);
} else {
reject('Error occured');
}
}
};
Http.onerror = error => {
reject('Error occured');
};
const url = 'https://api.acmecorp.com/skyflowToken';
Http.open('GET', url);
Http.send();
});
};
For logLevel
parameter, there are 4 accepted values in Skyflow.LogLevel
-
DEBUG
When Skyflow.LogLevel.DEBUG
is passed, all level of logs will be printed(DEBUG, INFO, WARN, ERROR).
-
INFO
When Skyflow.LogLevel.INFO
is passed, INFO logs for every event that has occurred during the SDK flow execution will be printed along with WARN and ERROR logs.
-
WARN
When Skyflow.LogLevel.WARN
is passed, WARN and ERROR logs will be printed.
-
ERROR
When Skyflow.LogLevel.ERROR
is passed, only ERROR logs will be printed.
Note
:
- The ranking of logging levels is as follows : DEBUG < INFO < WARN < ERROR
- since
logLevel
is optional, by default the logLevel will be ERROR
.
For env
parameter, there are 2 accepted values in Skyflow.Env
Note
:
- since
env
is optional, by default the env will be PROD
. - Use
env
option with caution, make sure the env is set to PROD
when using skyflow-js
in production.
Securely collecting data client-side
Insert data into the vault
To insert data into the vault, use the insert(records, options?)
method of the Skyflow client. The records
parameter takes a JSON object of the records to insert into the below format. The options
parameter takes a dictionary of optional parameters for the insertion. The insert
method also supports upsert operations.
const records = {
records: [
{
table: 'string',
fields: {
column1: 'value',
},
},
],
};
const options = {
tokens: true,
upsert: [
{
table: 'string',
column: 'value',
}
]
}
skyflowClient.insert(records, options);
An example of an insert call:
skyflowClient.insert({
records: [
{
table: 'cards',
fields: {
cardNumber: '41111111111',
cvv: '123',
},
},
],
});
The sample response:
{
"records": [
{
"table": "cards",
"fields":{
"cardNumber": "f3907186-e7e2-466f-91e5-48e12c2bcbc1",
"cvv": "1989cb56-63da-4482-a2df-1f74cd0dd1a5"
}
}
]
}
Using Skyflow Elements to collect data
Skyflow Elements provide developers with pre-built form elements to securely collect sensitive data client-side. These elements are hosted by Skyflow and injected into your web page as iFrames. This reduces your PCI compliance scope by not exposing your front-end application to sensitive data. Follow the steps below to securely collect data with Skyflow Elements on your web page.
Step 1: Create a container
First create a container for the form elements using the container(Skyflow.ContainerType)
method of the Skyflow client as show below:
const container = skyflowClient.container(Skyflow.ContainerType.COLLECT)
Step 2: Create a collect Element
A Skyflow collect Element is defined as shown below:
const collectElement = {
table: 'string',
column: 'string',
type: Skyflow.ElementType,
inputStyles: {},
labelStyles: {},
errorTextStyles: {},
label: 'string',
placeholder: 'string',
altText: 'string',
validations: [],
}
The table
and column
fields indicate which table and column in the vault the Element corresponds to.
Note:
- Use dot delimited strings to specify columns nested inside JSON fields (e.g.
address.street.line1
)
The inputStyles
field accepts a style object which consists of CSS properties that should be applied to the form element in the following states:
base
: all variants inherit from these stylescomplete
: applied when the Element has valid inputempty
: applied when the Element has no inputfocus
: applied when the Element has focusinvalid
: applied when the Element has invalid inputcardIcon
: applied to the card type icon in CARD_NUMBER ElementcopyIcon
: applied to copy icon in Elements when enableCopy option is true
Styles are specified with JSS.
An example of a inputStyles object:
inputStyles: {
base: {
border: '1px solid #eae8ee',
padding: '10px 16px',
borderRadius: '4px',
color: '#1d1d1d',
},
complete: {
color: '#4caf50',
},
empty: {},
focus: {},
invalid: {
color: '#f44336',
},
cardIcon: {
position: 'absolute',
left: '8px',
bottom: 'calc(50% - 12px)',
},
copyIcon: {
position: 'absolute',
right: '8px',
},
},
The states that are available for labelStyles
are base
and focus
.
An example of a labelStyles object:
labelStyles: {
base: {
fontSize: '12px',
fontWeight: 'bold',
},
focus: {
color: '#1d1d1d',
},
},
The state that is available for errorTextStyles
is only the base
state, it shows up when there is some error in the collect element.
An example of a errorTextStyles object:
errorTextStyles: {
base: {
color: '#f44336',
},
},
Finally, the type
field takes a Skyflow ElementType. Each type applies the appropriate regex and validations to the form element. There are currently 8 types:
CARDHOLDER_NAME
CARD_NUMBER
EXPIRATION_DATE
EXPIRATION_MONTH
EXPIRATION_YEAR
CVV
INPUT_FIELD
PIN
FILE_INPUT
The INPUT_FIELD
type is a custom UI element without any built-in validations. For information on validations, see validations.
Along with CollectElement we can define other options which takes a object of optional parameters as described below:
const options = {
required: false,
enableCardIcon: true,
format: String,
enableCopy: false,
};
required
parameter indicates whether the field is marked as required or not. If not provided, it defaults to false
enableCardIcon
parameter indicates whether the icon is visible for the CARD_NUMBER element, defaults to true
format
parameter takes string value and indicates the format pattern applicable to the element type, It's currently only applicable to EXPIRATION_DATE
and EXPIRATION_YEAR
element types.
enableCopy
parameter indicates whether the copy icon is visible in collect and reveal elements.
The values that are accepted for EXPIRATION_DATE
are
MM/YY
(default)MM/YYYY
YY/MM
YYYY/MM
The values that are accepted for EXPIRATION_YEAR
are
NOTE
: If not specified or invalid value is passed to the format
then it takes default value.
Once the Element object and options has been defined, add it to the container using the create(element, options)
method as shown below. The element
param takes a Skyflow Element object and options as defined above:
const collectElement = {
table: 'string',
column: 'string',
type: Skyflow.ElementType,
inputStyles: {},
labelStyles: {},
errorTextStyles: {},
label: 'string',
placeholder: 'string',
altText: 'string',
validations: [],
}
const options = {
required: false,
enableCardIcon: true,
format: String,
enableCopy: false,
};
const element = container.create(collectElement, options);
Step 3: Mount Elements to the DOM
To specify where the Elements will be rendered on your page, create placeholder <div>
elements with unique id
tags. For instance, the form below has 4 empty divs with unique ids as placeholders for 4 Skyflow Elements.
<form>
<div id="cardNumber"/>
<br/>
<div id="expireDate"/>
<br/>
<div id="cvv"/>
<br/>
<div id="pin"/>
<button type="submit">Submit</button>
</form>
Now, when the mount(domElement)
method of the Element is called, the Element will be inserted in the specified div. For instance, the call below will insert the Element into the div with the id "#cardNumber".
element.mount('#cardNumber');
you can use the unmount
method to reset any collect element to it's initial state.
element.unmount();
Step 4: Collect data from Elements
When the form is ready to be submitted, call the collect(options?)
method on the container object. The options
parameter takes a object of optional parameters as shown below:
tokens
: indicates whether tokens for the collected data should be returned or not. Defaults to 'true'additionalFields
: Non-PCI elements data to be inserted into the vault which should be in the records
object format as described in the above Insert data into vault section.upsert
: To support upsert operations while collecting data from Skyflow elements, pass the table and column marked as unique in the table.
const options = {
tokens: true,
additionalFields: {
records: [
{
table: 'string',
fields: {
column1: 'value',
},
},
],
},
upsert: [
{
table: 'string',
column: 'value',
},
],
};
container.collect(options);
End to end example of collecting data with Skyflow Elements
Sample Code:
const container = skyflowClient.container(Skyflow.ContainerType.COLLECT);
const element = container.create({
table: 'cards',
column: 'cardNumber',
inputstyles: {
base: {
color: '#1d1d1d',
},
cardIcon: {
position: 'absolute',
left: '8px',
bottom: 'calc(50% - 12px)',
},
},
labelStyles: {
base: {
fontSize: '12px',
fontWeight: 'bold',
},
},
errorTextStyles: {
base: {
color: '#f44336',
},
},
placeholder: 'Card Number',
label: 'card_number',
type: Skyflow.ElementType.CARD_NUMBER,
});
element.mount('#cardNumber');
const nonPCIRecords = {
records: [
{
table: 'cards',
fields: {
gender: 'MALE',
},
},
],
};
container.collect({
tokens: true,
additionalFields: nonPCIRecords,
});
Sample Response :
{
"records": [
{
"table": "cards",
"fields": {
"cardNumber": "f3907186-e7e2-466f-91e5-48e12c2bcbc1",
"gender": "12f670af-6c7d-4837-83fb-30365fbc0b1e"
}
}
]
}
Insert call example with upsert support
Sample Code
const container = skyflowClient.container(Skyflow.ContainerType.COLLECT)
const cardNumberElement = container.create({
table: 'cards',
column: 'card_number',
inputStyles: {
base: {
color: '#1d1d1d',
},
cardIcon:{
position: 'absolute',
left:'8px',
bottom:'calc(50% - 12px)'
},
},
labelStyles: {
base: {
fontSize: '12px',
fontWeight: 'bold'
}
},
errorTextStyles: {
base: {
color: '#f44336'
}
},
placeholder: 'Card Number',
label: 'card_number',
type: Skyflow.ElementType.CARD_NUMBER
})
const cvvElement = container.create({
table: 'cards',
column: 'cvv',
inputStyles: {
base: {
color: '#1d1d1d',
},
cardIcon:{
position: 'absolute',
left:'8px',
bottom:'calc(50% - 12px)'
},
},
labelStyles: {
base: {
fontSize: '12px',
fontWeight: 'bold'
}
},
errorTextStyles: {
base: {
color: '#f44336'
}
},
placeholder: 'CVV',
label: 'cvv',
type: Skyflow.ElementType.CVV
})
cardNumberElement.mount('#cardNumber')
cvvElement.mount('#cvv');
container.collect({
tokens: true,
upsert: [
{
table: 'cards',
column: 'card_number',
}
]
})
Skyflow returns tokens for the record you just inserted.
{
"records": [
{
"table": "cards",
"fields": {
"cardNumber": "f3907186-e7e2-466f-91e5-48e12c2bcbc1",
"gender": "12f670af-6c7d-4837-83fb-30365fbc0b1e"
}
}
]
}
Validations
Skyflow-JS provides two types of validations on Collect Elements
1. Default Validations:
Every Collect Element except of type INPUT_FIELD
has a set of default validations listed below:
CARD_NUMBER
: Card number validation with checkSum algorithm(Luhn algorithm).
Available card lengths for defined card types are [12, 13, 14, 15, 16, 17, 18, 19].
A valid 16 digit card number will be in the format - XXXX XXXX XXXX XXXX
CARD_HOLDER_NAME
: Name should be 2 or more symbols, valid characters should match pattern - ^([a-zA-Z\\ \\,\\.\\-\\']{2,})$
CVV
: Card CVV can have 3-4 digitsEXPIRATION_DATE
: Any date starting from current month. By default valid expiration date should be in short year format - MM/YY
PIN
: Can have 4-12 digits
2. Custom Validations:
Custom validations can be added to any element which will be checked after the default validations have passed. The following Custom validation rules are currently supported:
REGEX_MATCH_RULE
: You can use this rule to specify any Regular Expression to be matched with the input field value
const regexMatchRule = {
type: Skyflow.ValidationRuleType.REGEX_MATCH_RULE,
params: {
regex: RegExp,
error: string
}
}
LENGTH_MATCH_RULE
: You can use this rule to set the minimum and maximum permissible length of the input field value
const lengthMatchRule = {
type: Skyflow.ValidationRuleType.LENGTH_MATCH_RULE,
params: {
min : number,
max : number,
error: string
}
}
ELEMENT_VALUE_MATCH_RULE
: You can use this rule to match the value of one element with another element
const elementValueMatchRule = {
type: Skyflow.ValidationRuleType.ELEMENT_VALUE_MATCH_RULE,
params: {
element: CollectElement,
error: string
}
}
The Sample code snippet for using custom validations:
const alphabetsOnlyRegexRule = {
type: Skyflow.ValidationRuleType.REGEX_MATCH_RULE,
params: {
regex: /^[A-Za-z]+$/,
error: 'Only alphabets are allowed',
},
};
const lengthRule = {
type: Skyflow.ValidationRuleType.LENGTH_MATCH_RULE,
params: {
min: 4,
max: 6,
error: 'Must be between 4 and 6 alphabets',
},
};
const cardHolderNameElement = collectContainer.create({
table: 'pii_fields',
column: 'first_name',
...collectStylesOptions,
label: 'Card Holder Name',
placeholder: 'cardholder name',
type: Skyflow.ElementType.INPUT_FIELD,
validations: [alphabetsOnlyRegexRule, lengthRule],
});
const pinElement = collectContainer.create({
label: 'PIN',
placeholder: '****',
type: Skyflow.ElementType.PIN,
});
const elementMatchRule = {
type: Skyflow.ValidationRuleType.ELEMENT_VALUE_MATCH_RULE,
params: {
element: pinElement,
error: 'PIN does not match',
},
};
const confirmPinElement = collectContainer.create({
label: 'Confirm PIN',
placeholder: '****',
type: Skyflow.ElementType.PIN,
validations: [elementMatchRule],
});
pinElement.mount('#collectPIN');
confirmPinElement.mount('#collectConfirmPIN');
Event Listener on Collect Elements
Helps to communicate with Skyflow elements / iframes by listening to an event
element.on(Skyflow.EventName,handler:function)
There are 4 events in Skyflow.EventName
-
CHANGE
Change event is triggered when the Element's value changes.
-
READY
Ready event is triggered when the Element is fully rendered
-
FOCUS
Focus event is triggered when the Element gains focus
-
BLUR
Blur event is triggered when the Element loses focus.
The handler function(state) => void
is a callback function you provide, that will be called when the event is fired with the state object as shown below.
state : {
elementType: Skyflow.ElementType
isEmpty: boolean
isFocused: boolean
isValid: boolean
value: string
}
Note:
values of SkyflowElements will be returned in element state object only when env
is DEV
, else it is empty string i.e, '', but in case of CARD_NUMBER type element when the env
is PROD
for all the card types except AMEX, it will return first eight digits, for AMEX it will return first six digits and rest all digits in masked format.
Sample code snippet for using listeners
const skyflowClient = Skyflow.init({
vaultID: '<VAULT_ID>',
vaultURL: '<VAULT_URL>',
getBearerToken: () => {},
options: {
env: Skyflow.Env.DEV,
},
});
const container = skyflowClient.container(Skyflow.ContainerType.COLLECT);
const cardHolderName = container.create({
table: 'pii_fields',
column: 'first_name',
type: Skyflow.ElementType.CARDHOLDER_NAME,
});
const cardNumber = container.create({
table: 'pii_fields',
column: 'primary_card.card_number',
type: Skyflow.ElementType.CARD_NUMBER,
});
cardNumber.mount('#cardNumberContainer');
cardHolderName.mount('#cardHolderNameContainer');
cardHolderName.on(Skyflow.EventName.CHANGE, state => {
console.log(state);
});
cardNumber.on(Skyflow.EventName.CHANGE, state => {
console.log(state);
});
Sample Element state object when env
is DEV
{
elementType: 'CARDHOLDER_NAME',
isEmpty: false,
isFocused: true,
isValid: false,
value: 'John',
};
{
elementType: 'CARD_NUMBER',
isEmpty: false,
isFocused: true,
isValid: false,
value: '4111-1111-1111-1111',
};
Sample Element state object when env
is PROD
{
elementType: 'CARDHOLDER_NAME',
isEmpty: false,
isFocused: true,
isValid: false,
value: '',
};
{
elementType: 'CARD_NUMBER',
isEmpty: false,
isFocused: true,
isValid: false,
value: '4111-1111-XXXX-XXXX',
};
UI Error for Collect Elements
Helps to display custom error messages on the Skyflow Elements through the methods setError
and resetError
on the elements.
setError(error: string)
method is used to set the error text for the element, when this method is triggered, all the current errors present on the element will be overridden with the custom error message passed. This error will be displayed on the element until resetError()
is triggered on the same element.
resetError()
method is used to clear the custom error message that is set using setError
.
Sample code snippet for setError and resetError
const container = skyflowClient.container(Skyflow.ContainerType.COLLECT);
const cardNumber = container.create({
table: 'pii_fields',
column: 'primary_card.card_number',
type: Skyflow.ElementType.CARD_NUMBER,
});
cardNumber.setError('custom error');
cardNumber.resetError();
Set and Clear value for Collect Elements (DEV ENV ONLY)
setValue(value: string)
method is used to set the value of the element. This method will override any previous value present in the element.
clearValue()
method is used to reset the value of the element.
Note:
This methods are only available in DEV env for testing/developmental purposes and MUST NOT be used in PROD env.
Sample code snippet for setValue and clearValue
const container = skyflowClient.container(Skyflow.ContainerType.COLLECT);
const cardNumber = container.create({
table: 'pii_fields',
column: 'primary_card.card_number',
type: Skyflow.ElementType.CARD_NUMBER,
});
cardNumber.setValue('4111111111111111');
cardNumber.clearValue();
Securely collecting data client-side using Composable Elements
Composable Elements combine multiple Skyflow Elements in a single iframe, letting you create multiple Skyflow Elements in a single row. The following steps create a composable element and securely collect data through it.
Step 1: Create a composable container
Create a container for the composable element using the container(Skyflow.ContainerType)
method of the Skyflow client:
const collectContainer = skyflow.container(Skyflow.ContainerType.COMPOSABLE,containerOptions);
The container requires an options object that contains the following keys:
-
layout
: An array that indicates the number of rows in the container and the number of elements in each row. The index value of the array defines the number of rows, and each value in the array represents the number of elements in that row, in order.
For example: [2,1]
means the container has two rows, with two elements in the first row and one element in the second row.
Note
: The sum of values in the layout array should be equal to the number of elements created
-
styles
: CSS styles to apply to the composable container.
-
errorTextStyles
: CSS styles to apply if an error is encountered.
const options = {
layout: [2, 1],
styles: {
base: {
border: '1px solid #DFE3EB',
padding: '8px',
borderRadius: '4px',
margin: '12px 2px',
},
},
errorTextStyles: {
base: {
color: 'red',
},
},
};
Step 2: Create Composable Elements
Composable Elements use the following schema:
const composableElement = {
table: 'string',
column: 'string',
type: Skyflow.ElementType,
inputStyles: {},
labelStyles: {},
errorTextStyles: {},
label: 'string',
placeholder: 'string',
altText: 'string',
validations: [],
}
The table
and column
fields indicate which table and column in the vault the Element correspond to.
Note: Use dot-delimited strings to specify columns nested inside JSON fields (for example, address.street.line1
).
All elements can be styled with JSS syntax.
The inputStyles
field accepts an object of CSS properties to apply to the form element in the following states:
base
: all variants inherit from these stylescomplete
: applied when the Element has valid inputempty
: applied when the Element has no inputfocus
: applied when the Element has focusinvalid
: applied when the Element has invalid inputcardIcon
: applied to the card type icon in CARD_NUMBER ElementcopyIcon
: applied to copy icon in Elements when enableCopy option is true
An example of an inputStyles
object:
inputStyles: {
base: {
border: '1px solid #eae8ee',
padding: '10px 16px',
borderRadius: '4px',
color: '#1d1d1d',
},
complete: {
color: '#4caf50',
},
empty: {},
focus: {},
invalid: {
color: '#f44336',
},
cardIcon: {
position: 'absolute',
left: '8px',
bottom: 'calc(50% - 12px)',
},
copyIcon: {
position: 'absolute',
right: '8px',
},
}
The labelStyles
field supports the base
and focus
states.
An example labelStyles
object:
labelStyles: {
base: {
fontSize: '12px',
fontWeight: 'bold'
},
focus: {
color: '#1d1d1d'
}
}
The errorTextStyles
field only supports the base
state, which appears when there is an error in the composable element.
An example errorTextStyles
object:
errorTextStyles: {
base: {
color: '#f44336'
}
}
The JS SDK supports the following composable elements:
CARDHOLDER_NAME
CARD_NUMBER
EXPIRATION_DATE
EXPIRATION_MONTH
EXPIRATION_YEAR
CVV
INPUT_FIELD
PIN
Note
: Only when the entered value in the below composable elements is valid, the focus shifts automatically. The element types are:
CARD_NUMBER
EXPIRATION_DATE
EXPIRATION_MONTH
EXPIRATION_YEAR
The INPUT_FIELD
type is a custom UI element without any built-in validations. For information on validations, see validations.
Along with the Composable Element definition, you can define additional options for the element:
const options = {
required: false,
enableCardIcon: true,
format: String,
enableCopy: false
}
required
: Whether or not the field is marked as required. Defaults to false
.enableCardIcon
: Whether or not the icon is visible for the CARD_NUMBER element. Defaults to true
.format
: Format pattern for the element. Only applicable to EXPIRATION_DATE and EXPIRATION_YEAR element types.enableCopy
: Whether or not the copy icon is visible in collect and reveal elements. Defaults to false
.
The accepted EXPIRATION_DATE
values are
MM/YY
(default)MM/YYYY
YY/MM
YYYY/MM
The accepted EXPIRATION_YEAR
values are
Once you define the Element object and options, add it to the container using the create(element, options)
method:
const composableElement = {
table: 'string',
column: 'string',
type: Skyflow.ElementType,
inputStyles: {},
labelStyles: {},
errorTextStyles: {},
label: 'string',
placeholder: 'string',
altText: 'string',
validations: [],
}
const options = {
required: false,
enableCardIcon: true,
format: String,
enableCopy: false,
};
const element = container.create(composableElement, options);
Step 3: Mount Container to the DOM
To specify where the Elements are rendered on your page, create a placeholder <div>
element with unique id
attribute. Use this empty <div>
placeholder to mount the composable container.
<form>
<div id="composableContainer"/>
<br/>
<div id="button-id"/>
<button type="submit">Submit</button>
</form>
Use the composable container's mount(domElement)
method to insert the container's Elements into the specified <div>
. For instance, the following call inserts Elements into the <div>
with the id "#composableContainer"
.
container.mount('#composableContainer');
Step 4: Collect data from elements
When the form is ready to be submitted, call the container's collect(options?)
method. The options parameter takes an object of optional parameters as follows:
tokens
: Whether or not tokens for the collected data are returned. Defaults to 'true'additionalFields
: Non-PCI elements data to insert into the vault, specified in the records object format.upsert
: To support upsert operations, the table containing the data and a column marked as unique in that table.
const options = {
tokens: true,
additionalFields: {
records: [
{
table: 'string',
fields: {
column1: 'value',
},
},
],
},
upsert: [
{
table: 'string',
column: 'value',
},
],
};
End to end example of collecting data with Composable Elements
const containerOptions = {
layout: [2, 1],
styles: {
base: {
border: '1px solid #eae8ee',
padding: '10px 16px',
borderRadius: '4px',
margin: '12px 2px',
},
},
errorTextStyles: {
base: {
color: 'red',
},
},
};
const composableContainer = skyflow.container(
Skyflow.ContainerType.COMPOSABLE,
containerOptions
);
const collectStylesOptions = {
inputStyles: {
base: {
fontFamily: 'Inter',
fontStyle: 'normal',
fontWeight: 400,
fontSize: '14px',
lineHeight: '21px',
width: '294px',
},
},
labelStyles: {},
errorTextStyles: {
base: {},
},
};
const cardHolderNameElement = composableContainer.create({
table: 'pii_fields',
column: 'first_name',
...collectStylesOptions,
placeholder: 'Cardholder Name',
type: Skyflow.ElementType.CARDHOLDER_NAME,
});
const cardNumberElement = composableContainer.create({
table: 'pii_fields',
column: 'card_number',
...collectStylesOptions,
placeholder: 'Card Number',
type: Skyflow.ElementType.CARD_NUMBER,
});
const cvvElement = composableContainer.create({
table: 'pii_fields',
column: 'cvv',
...collectStylesOptions,
placeholder: 'CVV',
type: Skyflow.ElementType.CVV,
});
composableContainer.mount('#composableContainer');
composableContainer.collect({
tokens: true,
});
Sample Response:
{
"records": [
{
"table": "pii_fields",
"fields": {
"first_name": "63b5eeee-3624-493f-825e-137a9336f882",
"card_number": "f3907186-e7e2-466f-91e5-48e12c2bcbc1",
"cvv": "7baf5bda-aa22-4587-a5c5-412f6f783a19",
}
}
]
}
For information on validations, see validations.
Set an event listener on Composable Elements:
You can communicate with Skyflow Elements by listening to element events:
element.on(Skyflow.EventName,handler:function)
The SDK supports four events:
CHANGE
: Triggered when the Element's value changes.READY
: Triggered when the Element is fully rendered.FOCUS
: Triggered when the Element gains focus.BLUR
: Triggered when the Element loses focus.
The handler function(state) => void
is a callback function you provide that's called when the event is fired with a state object that uses the following schema:
state : {
elementType: Skyflow.ElementType
isEmpty: boolean
isFocused: boolean
isValid: boolean
value: string
}
Note
: Events only include element values when in the state object when env is DEV. By default, value is an empty string.
Example Usage of Event Listener on Composable Elements
const containerOptions = {
layout: [1],
styles: {
base: {
border: '1px solid #eae8ee',
padding: '10px 16px',
borderRadius: '4px',
margin: '12px 2px',
}
},
errorTextStyles: {
base: {
color: 'red'
}
}
}
const composableContainer = skyflow.container(Skyflow.ContainerType.COMPOSABLE, containerOptions);
const cvv = composableContainer.create({
table: 'pii_fields',
column: 'primary_card.cvv',
type: Skyflow.ElementType.CVV,
});
composableContainer.mount('#cvvContainer');
cvv.on(Skyflow.EventName.CHANGE, state => {
console.log(state);
});
Sample Element state object when env is DEV
{
elementType: 'CVV'
isEmpty: false
isFocused: true
isValid: false
value: '411'
}
Sample Element state object when env is PROD
{
elementType: 'CVV'
isEmpty: false
isFocused: true
isValid: false
value: ''
}
Securely revealing data client-side
Retrieving data from the vault
For non-PCI use-cases, retrieving data from the vault and revealing it in the browser can be done either using the SkyflowID's or tokens as described below
-
Using Skyflow tokens
In order to retrieve data from your vault using tokens that you have previously generated for that data, you can use the detokenize(records)
method. The records parameter takes a JSON object that contains records
to be fetched as shown below.
const records = {
records: [
{
token: 'string',
redaction: RedactionType
},
],
};
Note: If you do not provide a redaction type, RedactionType.PLAIN_TEXT is the default.
skyflow.detokenize(records);
An example of a detokenize call:
skyflow.detokenize({
records: [
{
token: '131e70dc-6f76-4319-bdd3-96281e051051',
},
{
token: '1r434532-6f76-4319-bdd3-96281e051051',
redaction: Skyflow.RedactionType.MASKED
}
],
});
The sample response:
{
"records": [
{
"token": "131e70dc-6f76-4319-bdd3-96281e051051",
"value": "1990-01-01",
},
{
"token": "1r434532-6f76-4319-bdd3-96281e051051",
"value": "xxxxxxer",
}
]
}
-
Using Skyflow ID's
In order to retrieve data from your vault using SkyflowIDs, use the getById(records)
method.The records parameter takes a JSON object that contains records
to be fetched as shown below.
{
records: [
{
ids: string[],
table: string,
redaction: Skyflow.RedactionType,
}
]
}
There are 4 accepted values in Skyflow.RedactionTypes:
PLAIN_TEXT
MASKED
REDACTED
DEFAULT
An example of getById call:
skyflow.getById({
records: [
{
ids: ['f8d8a622-b557-4c6b-a12c-c5ebe0b0bfd9'],
table: 'cards',
redaction: Skyflow.RedactionType.PLAIN_TEXT,
},
{
ids: ['da26de53-95d5-4bdb-99db-8d8c66a35ff9'],
table: 'contacts',
redaction: Skyflow.RedactionType.PLAIN_TEXT,
},
],
});
The sample response:
{
"records": [
{
"fields": {
"card_number": "4111111111111111",
"cvv": "127",
"expiry_date": "11/2035",
"fullname": "myname",
"id": "f8d8a622-b557-4c6b-a12c-c5ebe0b0bfd9"
},
"table": "cards"
}
],
"errors": [
{
"error": {
"code": "404",
"description": "No Records Found"
},
"ids": ["da26de53-95d5-4bdb-99db-8d8c66a35ff9"]
}
]
}
Using Skyflow Elements to reveal data
Skyflow Elements can be used to securely reveal data in a browser without exposing your front end to the sensitive data. This is great for use cases like card issuance where you may want to reveal the card number to a user without increasing your PCI compliance scope.
Step 1: Create a container
To start, create a container using the container(Skyflow.ContainerType)
method of the Skyflow client as shown below.
const container = skyflowClient.container(Skyflow.ContainerType.REVEAL)
Step 2: Create a reveal Element
Then define a Skyflow Element to reveal data as shown below.
const revealElement = {
token: 'string',
inputStyles: {},
labelStyles: {},
errorTextStyles: {},
label: 'string',
altText: 'string',
redaction: RedactionType,
};
Note: If you don't provide a redaction type, RedactionType.PLAIN_TEXT will apply by default.
The inputStyles
, labelStyles
and errorTextStyles
parameters accepts a styles object as described in the previous section for collecting data. But for reveal element, inputStyles
accepts only base
variant and copyIcon
style object.
An example of a inputStyles object:
inputStyles: {
base: {
color: '#1d1d1d',
},
copyIcon: {
position: 'absolute',
right: '8px',
top: 'calc(50% - 10px)',
},
},
An example of a labelStyles object:
labelStyles: {
base: {
fontSize: '12px',
fontWeight: 'bold',
},
},
An example of a errorTextStyles object:
errorTextStyles: {
base: {
color: '#f44336',
},
},
Once you've defined a Skyflow Element, you can use the create(element)
method of the container to create the Element as shown below:
const element = container.create(revealElement)
Step 3: Mount Elements to the DOM
Elements used for revealing data are mounted to the DOM the same way as Elements used for collecting data. Refer to Step 3 of the section above.
Step 4: Reveal data
When the sensitive data is ready to be retrieved and revealed, call the reveal()
method on the container as shown below:
container
.reveal()
.then(data => {
})
.catch(err => {
});
End to end example of all steps
Sample Code:
const container = skyflowClient.container(Skyflow.ContainerType.REVEAL);
const cardNumberElement = container.create({
token: 'b63ec4e0-bbad-4e43-96e6-6bd50f483f75',
inputStyles: {
base: {
color: '#1d1d1d',
},
},
labelStyles: {
base: {
fontSize: '12px',
},
},
errorTextStyles: {
base: {
color: '#f44336',
},
},
label: 'card_number',
altText: 'XXXX XXXX XXXX XXXX',
redaction: SKyflow.RedactionType.MASKED
});
const cvvElement = container.create({
token: '89024714-6a26-4256-b9d4-55ad69aa4047',
inputStyles: {
base: {
color: '#1d1d1d',
},
},
label: 'cvv',
altText: 'XXX',
});
const expiryDate= container.create({
token: 'a4b24714-6a26-4256-b9d4-55ad69aa4047',
inputStyles: {
base: {
color: '#1d1d1d',
},
},
label: 'expiryDate',
altText: 'MM/YYYY',
});
cardNumberElement.mount('#cardNumber');
cvvElement.mount('#cvv');
expiryDate.mount('#expiryDate');
container
.reveal()
.then(data => {
})
.catch(err => {
});
The response below shows that some tokens assigned to the reveal elements get revealed successfully, while others fail and remain unrevealed.
Sample Response
{
"success": [
{
"token": "b63ec4e0-bbad-4e43-96e6-6bd50f483f75",
"value": "xxxxxxxxx4163"
},
{
"token": "a4b24714-6a26-4256-b9d4-55ad69aa4047",
"value": "12/2098"
}
],
"errors": [
{
"token": "89024714-6a26-4256-b9d4-55ad69aa4047",
"error": {
"code": 404,
"description": "Tokens not found for 89024714-6a26-4256-b9d4-55ad69aa4047"
}
}
]
}
UI Error for Reveal Elements
Helps to display custom error messages on the Skyflow Elements through the methods setError
and resetError
on the elements.
setError(error: string)
method is used to set the error text for the element, when this method is triggered, all the current errors present on the element will be overridden with the custom error message passed. This error will be displayed on the element until resetError()
is triggered on the same element.
resetError()
method is used to clear the custom error message that is set using setError
.
Sample code snippet for setError and resetError
const container = skyflowClient.container(Skyflow.ContainerType.REVEAL);
const cardNumber = container.create({
token: '89024714-6a26-4256-b9d4-55ad69aa4047',
});
cardNumber.setError('custom error');
cardNumber.resetError();
Set token for Reveal Elements
The setToken(value: string)
method can be used to set the token of the Reveal Element. If no altText is set, the set token will be displayed on the UI as well. If altText is set, then there will be no change in the UI but the token of the element will be internally updated.
Sample code snippet for setToken
const container = skyflowClient.container(Skyflow.ContainerType.REVEAL);
const cardNumber = container.create({
altText: 'Card Number',
});
cardNumber.setToken('89024714-6a26-4256-b9d4-55ad69aa4047');
Set and Clear altText for Reveal Elements
The setAltText(value: string)
method can be used to set the altText of the Reveal Element. This will cause the altText to be displayed in the UI regardless of whether the token or value is currently being displayed.
clearAltText()
method can be used to clear the altText, this will cause the element to display the token or actual value of the element. If the element has no token, the element will be empty.
Sample code snippet for setAltText and clearAltText
const container = skyflowClient.container(Skyflow.ContainerType.REVEAL);
const cardNumber = container.create({
token: '89024714-6a26-4256-b9d4-55ad69aa4047',
});
cardNumber.setAltText('Card Number');
cardNumber.clearAltText();
Using Skyflow File Element to upload a file
You can upload binary files to a vault using the Skyflow File Element. Use the following steps to securely upload a file.
Step 1: Create a container
Create a container for the form elements using the container(Skyflow.ContainerType) method of the Skyflow client:
const container = skyflowClient.container(Skyflow.ContainerType.COLLECT)
Step 2: Create a File Element
Skyflow Collect Elements are defined as follows:
const collectElement = {
type: Skyflow.ElementType.FILE_INPUT,
table: 'string',
column: 'string',
skyflowID: 'string',
inputStyles: {},
labelStyles: {},
errorTextStyles:{},
}
The table
and column
fields indicate which table and column the Element corresponds to.
skyflowID
indicates the record that stores the file.
Notes:
skyflowID
is required while creating File element- Use period-delimited strings to specify columns nested inside JSON fields (e.g.
address.street.line1
).
Step 3: Mount elements to the DOM
To specify where to render Elements on your page, create placeholder <div>
elements with unique id
tags. For instance, the form below has an empty div with a unique id as a placeholder for a Skyflow Element.
<form>
<div id="file"/>
<br/>
<button type="submit">Submit</button>
</form>
Now, when the mount(domElement)
method of the Element is called, the Element is inserted in the specified div. For instance, the call below inserts the Element into the div with the id "#file".
element.mount('#file');
Use the unmount
method to reset a Collect Element to its initial state.
element.unmount();
Step 4: Collect data from elements
When the file is ready to be uploaded, call the uploadFiles()
method on the container object.
container.uploadFiles();
File upload limitations:
- Only non-executable file are allowed to be uploaded.
- Files must have a maximum size of 32 MB
- File columns can't enable tokenization, redaction, or arrays.
- Re-uploading a file overwrites previously uploaded data.
- Partial uploads or resuming a previous upload isn't supported.
End-to-end file upload
const container = skyflowClient.container(Skyflow.ContainerType.COLLECT);
const element = container.create({
table: 'pii_fields',
column: 'file',
skyflowID: '431eaa6c-5c15-4513-aa15-29f50babe882',
inputstyles: {
base: {
color: '#1d1d1d',
},
},
labelStyles: {
base: {
fontSize: '12px',
fontWeight: 'bold',
},
},
errorTextStyles: {
base: {
color: '#f44336',
},
},
type: Skyflow.ElementType.FILE_INPUT,
});
element.mount('#file');
container.uploadFiles();
Sample Response :
{
fileUploadResponse: [
{
"skyflow_id": "431eaa6c-5c15-4513-aa15-29f50babe882"
}
]
}
File upload with additional elements
const collectContainer = skyflow.container(Skyflow.ContainerType.COLLECT);
const cardNumberElement = collectContainer.create({
table: 'newTable',
column: 'card_number',
inputstyles: {
base: {
color: '#1d1d1d',
},
},
labelStyles: {
base: {
fontSize: '12px',
fontWeight: 'bold',
},
},
errorTextStyles: {
base: {
color: '#f44336',
},
},
placeholder: 'card number',
label: 'Card Number',
type: Skyflow.ElementType.CARD_NUMBER,
});
const fileElement = collectContainer.create({
table: 'newTable',
column: 'file',
skyflowID: '431eaa6c-5c15-4513-aa15-29f50babe882',
inputstyles: {
base: {
color: '#1d1d1d',
},
},
labelStyles: {
base: {
fontSize: '12px',
fontWeight: 'bold',
},
},
errorTextStyles: {
base: {
color: '#f44336',
},
},
type: Skyflow.ElementType.FILE_INPUT,
});
cardNumberElement.mount('#collectCardNumber');
fileElement.mount('#collectFile');
container.collect({});
container.uploadFiles();
Sample Response for collect():
{
"records": [
{
"table": "newTable",
"fields": {
"card_number": "f3907186-e7e2-466f-91e5-48e12c2bcbc1",
}
}
]
}
Sample Response for file uploadFiles() :
{
"fileUploadResponse": [
{
"skyflow_id": "431eaa6c-5c15-4513-aa15-29f50babe882"
}
]
}
Reporting a Vulnerability
If you discover a potential security issue in this project, please reach out to us at security@skyflow.com. Please do not create public GitHub issues or Pull Requests, as malicious actors could potentially view them.