Cybersource Microform
Cybersource Microform is Cybersource's embedded, PCI-compliant card-entry widget. It renders card fields inside iframes on your checkout page — card details never touch your servers.
Centra's Cybersource plugin uses the Flex Microform v2 API and handles:
- Generating a Capture Context JWT that authorizes Microform to render on your domain.
- Payment authorization with direct capture — authorization and capture in one step (no separate capture request).
- 3D Secure 2.0 payer authentication setup, device fingerprinting orchestration, enrollment check, and challenge flow.
- JWS/MLE mutual authentication for enhanced API-level security (optional, requires activation on your Cybersource account).
The frontend partner implements:
- Loading and rendering Cybersource Microform using the Capture Context.
- Collecting card data and obtaining a Transient Token JWT via Microform.
- Driving 3DS device fingerprinting and the optional challenge window.
Supported APIs: Cybersource Microform works with the Storefront API and the Checkout API (Legacy).
Plugin configuration (Centra admin)
Required credentials
Merchant ID
Your Cybersource merchant account identifier, found in the Business Center.
API Key
The key ID of your Cybersource REST API credentials. Generate this in the Business Center under Payment Configuration → Key Management → Generate Key → REST Shared Secret.
API Shared Secret
The shared secret paired with the API Key above. Centra uses it to sign all requests via HMAC-SHA256 HTTP Signature authentication. Keep it secret — treat it like a password.
Target origins
Comma-separated list of HTTPS origins (scheme + host + optional port — no trailing path, query string, or fragment) where Cybersource Microform will be embedded.
Examples:
https://checkout.example.com,https://www.example.com
Exceptions allowed for local development: http://localhost, http://127.0.0.1.
| Valid origins | Invalid origins |
|---|---|
https://checkout.example.com | https://checkout.example.com/payment |
http://localhost | https://checkout.example.com?ref=1 |
http://localhost:8080 | https://shop.brand.com#step2 |
https://shop.brand.com |
Cybersource Microform refuses to initialize on an origin that is not in this list, so ensure every checkout domain (including staging environments) is listed.
Allowed card networks
Select the card brands that Microform will accept. Attempting to enter a card from an unlisted network will fail at the Microform level before submission.
| Value | Label |
|---|---|
| VISA | Visa |
| MASTERCARD | Mastercard |
| AMEX | American Express |
| DINERSCLUB | Diners Club |
| DISCOVER | Discover |
| JCB | JCB |
| MAESTRO | Maestro |
| CUP | China UnionPay |
| CARTESBANCAIRES | Cartes Bancaires |
| ELO | Elo |
| MADA | Mada |
| MEEZA | Meeza |
| UATP | UATP |
| CARNET | Carnet |
| EFTPOS | EFTPOS |
| JAYWAN | Jaywan |
| JCREW | J.Crew |
| KCP | KCP |
| PAYPAK | PayPak |
Test mode
Set to Yes to use Cybersource's sandbox environment. Set to No for production.
In test mode, Centra uses the sandbox Capture Context endpoint and Microform loads from https://testflex.cybersource.com. In production, requests go to https://api.cybersource.com and Microform loads from https://flex.cybersource.com.
3D-Secure settings
Payer authentication (3D-Secure) enabled
- Yes (default) — Centra runs the full 3DS 2.0 flow: payer authentication setup → device fingerprinting → enrollment check. Depending on the issuer's response, the flow is either frictionless (no user interaction) or requires a challenge window.
- No — Centra skips 3DS and goes straight to authorization. Only use this when you have a specific agreement with Cybersource and your acquirer, or when you are testing other parts of the integration and don't want to be distracted by the additional payer authentication steps.
Ignore AVS result
When Yes, Centra instructs Cybersource to proceed with capture even if the address verification (AVS) check returns a decline. Defaults to No.
Useful for merchants who accept international cards where AVS matching rates are low, but only enable this after confirming the risk profile with your acquirer.
Authentication method
Centra supports two API authentication methods for communicating with Cybersource:
| Method | Description |
|---|---|
| HTTP Signature (default) | HMAC-SHA256 signing of request headers using your API Key and Shared Secret. No additional setup required beyond the credentials above. |
| JWS/MLE | JSON Web Signature (request body signing) combined with Message-Level Encryption (request payload encryption with Cybersource's public key; response decryption with your private key). Requires separate key pairs and activation on the Cybersource side. |
Switch to JWS/MLE only when Cybersource requires it for your account or when your security requirements mandate payload-level encryption in transit.
JWS/MLE key configuration
When JWS/MLE is selected as the authentication method, three key pairs must be configured in the plugin:
| Field | Description |
|---|---|
| MLE Encryption Key ID | Key serial number (KSN) of the Cybersource-provided public certificate used to encrypt request payloads sent to Cybersource. Obtain this from your Business Center under Key Management. |
| MLE Encryption Key Contents | PEM-encoded public key. Paste the entire block, including -----BEGIN PUBLIC KEY----- and -----END PUBLIC KEY-----. |
| MLE Decryption Key ID | Key ID of your private key that Cybersource uses to address encrypted responses to you. |
| MLE Decryption Key Contents | Full PEM-encoded RSA private key used to decrypt Cybersource's encrypted API responses. Paste the entire block including -----BEGIN PRIVATE KEY----- and -----END PRIVATE KEY-----. |
| JWS Signature Key ID | Key ID of your private key used to sign request bodies with JWS. |
| JWS Signature Key Contents | Full PEM-encoded private key used for JWS signing. |
Centra only checks that each key ID is non-empty and that each key contents block is a valid PEM (public or private key). It does not verify that the key ID matches the provided key material — a mismatch will not be caught on save and will cause Cybersource to reject requests at runtime.
Key rotation
When you rotate MLE or JWS keys in the Cybersource Business Center:
- In the Business Center, generate or obtain the new key pair (Payment Configuration → Key Management). Note the new key ID.
- In the Centra admin, open the Cybersource plugin.
- Update both the key ID field and the key contents field for each key you are rotating. Always update both together — updating only one of them will not be caught on save, but will cause Cybersource to reject all subsequent payment requests.
- Save the plugin. Centra begins using the new keys immediately for all subsequent requests.
Cybersource supports an overlapping validity window for MLE certificates — the old and new certificates are both accepted by Cybersource during the transition period. Schedule the Centra plugin update during this overlap to avoid declined payments.
For JWS signing keys, verify with Cybersource whether an overlap window applies to your account. If not, coordinate the Centra plugin update as close to the Cybersource-side key activation time as possible.
Restrictions
The plugin supports standard Centra payment restrictions: by market, pricelist, country, and language. These work identically to all other Centra payment plugins.
Flow
Centra's Cybersource integration always uses direct capture — authorization and capture happen in a single Cybersource API call. There is no separate capture step.
Standard authorization (3D-Secure disabled or bypassed)
This path applies when payer_authentication_enabled is No, or when threeDSecurePreference: standard-authorization is passed in the payment submission request.
3D-Secure — frictionless flow
The frictionless path occurs when the card issuer authenticates the transaction without requiring an interactive challenge from the shopper (typically low-risk transactions with sufficient device fingerprint data).
3D-Secure — challenge flow
The challenge path occurs when the issuer requires the shopper to complete an interactive step-up authentication (e.g., OTP, biometric, or bank app).
Frontend implementation
Step 1 — Payment instructions
Call paymentInstructions to receive the Capture Context JWT. The Capture Context is a short-lived signed token that authorizes Microform to initialize on your domain and collect card data.
Storefront API:
mutation paymentInstructions($input: PaymentInstructionsInput!) {
paymentInstructions(input: $input) {
action {
__typename
... on FormPaymentAction {
formType
formFields
}
}
userErrors {
message
path
}
}
}
Validate the action shape before proceeding:
const action = response.paymentInstructions?.action;
if (
action?.__typename !== 'FormPaymentAction' ||
action.formType !== 'cybersource'
) {
// Unsupported response — surface an error or fallback
return;
}
const { captureContext } = action.formFields;
Step 2 — Load Cybersource Microform
Load the Microform script and initialize it with the Capture Context.
| Mode | Microform script URL |
|---|---|
| Test (sandbox) | https://testflex.cybersource.com/microform/bundle/v2/flex-microform.min.js |
| Production | https://flex.cybersource.com/microform/bundle/v2/flex-microform.min.js |
The captureContext JWT tells Microform which card networks are allowed and verifies that it is rendering on an authorized target origin. Microform will refuse to initialize if the current page origin is not listed in the Centra plugin's Target origins field.
// After loading the Microform script
const flex = new Flex(captureContext);
const microform = flex.microform();
const cardNumber = microform.createField('number', { placeholder: 'Card number' });
const securityCode = microform.createField('securityCode', { placeholder: 'CVV' });
cardNumber.load('#card-number-container');
securityCode.load('#security-code-container');
load() replaces the element at the given ID with a Cybersource-hosted iframe. These two fields are the only ones rendered by Microform — expiration month and year are regular form inputs you collect separately and pass to createToken(). Your page never has direct access to raw card data entered into the iframes.
Microform provides built-in client-side behaviour: it detects the card type as the number is entered, auto-formats the number with spaces based on the detected card type, and adjusts the expected CVV length accordingly.
Step 3 — Obtain a transient token
When the shopper submits the payment form, call microform.createToken() to tokenize the entered card data. The resulting Transient Token JWT represents the card for one-time use in authorization.
const options = {
expirationMonth: '12', // from your expiry month input
expirationYear: '2030', // from your expiry year input
};
microform.createToken(options, (error, transientToken) => {
if (error) {
// Validation errors (e.g. invalid card number) or network error
console.error(error);
return;
}
// Proceed to payment submission with both captureContext and transientToken
submitPayment(captureContext, transientToken);
});
Step 4 — Payment submission (first call)
Call paymentSubmission with both JWTs. At this point, Centra either:
- Proceeds to standard authorization (if 3DS is disabled or
standard-authorizationis requested). - Returns 3DS setup data for device fingerprinting (if 3DS is enabled).
Required fields (paymentMethodSpecificFields):
| Field | Type | Description |
|---|---|---|
captureContext | string (JWT) | The JWT received from paymentInstructions. |
transientToken | string (JWT) | The JWT received from microform.createToken(). |
Optional fields:
| Field | Type | Description |
|---|---|---|
threeDSecurePreference | string | One of: standard-authorization, frictionless, challenge. Omit to use the plugin default (3DS if enabled). |
threeDSecurePreference requires a server-to-server callBecause this field influences the security level of the transaction, Centra only accepts it when the request is authenticated with the shared secret. A call from the browser without shared secret authentication will be rejected with HTTP 400 if this field is present.
Checkout API example:
{
"paymentMethodSpecificFields": {
"captureContext": "<captureContext JWT>",
"transientToken": "<transientToken JWT>"
}
}
threeDSecurePreference values:
| Value | Effect |
|---|---|
standard-authorization | Skip 3DS for this payment regardless of plugin setting. |
frictionless | Request frictionless 3DS from the issuer (issuer may still challenge). |
challenge | Explicitly request a challenge from the issuer. |
Step 5 — Handle 3DS setup response
When 3DS is active and no payerAuthentication was in the request, Centra responds with action: javascript and the following formFields:
{
"captureContext": "<captureContext JWT>",
"transientToken": "<transientToken JWT>",
"payerAuthentication": {
"accessToken": "<JWT — POST this to the DDC iframe as field 'JWT'>",
"deviceDataCollectionUrl": "<Cardinal Commerce DDC endpoint — use this value as-is>",
"referenceId": "<UUID — pass back in the enrollment check>"
}
}
Always use deviceDataCollectionUrl exactly as returned by Centra — do not hardcode or reconstruct it. Cybersource provides different endpoints for sandbox (centinelapistag.cardinalcommerce.com) and production (centinelapi.cardinalcommerce.com), and the URL may change without notice.
Store captureContext, transientToken, and payerAuthentication.referenceId — all three are needed for the enrollment check call.
Step 6 — Device fingerprinting
Perform device fingerprinting by posting to deviceDataCollectionUrl inside a hidden iframe. This collects browser and device signals that the issuer uses for risk assessment.
<!-- Hidden iframe for device data collection -->
<iframe
id="ddc-iframe"
name="ddc-iframe"
style="display:none;"
height="1"
width="1"
></iframe>
<!-- Form targeting the hidden iframe -->
<form
id="ddc-form"
target="ddc-iframe"
method="POST"
action="{deviceDataCollectionUrl}"
>
<input type="hidden" name="JWT" value="{payerAuthentication.accessToken}" />
</form>
// Listen for completion before submitting enrollment check
window.addEventListener('message', (event) => {
let data;
try {
data = JSON.parse(event.data);
} catch {
return;
}
if (data.MessageType === 'profile.completed') {
// Device fingerprinting is done — proceed to enrollment check
checkEnrollment();
}
});
document.getElementById('ddc-form').submit();
Verify event.origin matches the origin of deviceDataCollectionUrl before trusting the message content.
While waiting for the fingerprinting event, collect the device information fields that are required for the enrollment check:
const deviceInformation = {
ipAddress: '<shopper IP — collect server-side>',
httpAcceptBrowserValue: 'text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8',
httpAcceptContent: 'text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8',
httpBrowserLanguage: navigator.language,
httpBrowserJavaEnabled: navigator.javaEnabled?.() ?? false,
httpBrowserJavaScriptEnabled: true,
httpBrowserColorDepth: String(screen.colorDepth),
httpBrowserScreenHeight: String(screen.height),
httpBrowserScreenWidth: String(screen.width),
httpBrowserTimeDifference: new Date().getTimezoneOffset().toString(),
userAgentBrowserValue: navigator.userAgent,
};
The shopper's IP address must be collected server-side (from the HTTP request headers) and passed to the client, or fetched via a dedicated endpoint — JavaScript in the browser cannot reliably read the true client IP.
Step 7 — Enrollment check (second paymentSubmission call)
Once device fingerprinting is complete, call paymentSubmission a second time with the payerAuthentication object:
{
"paymentMethodSpecificFields": {
"captureContext": "<captureContext JWT>",
"transientToken": "<transientToken JWT>",
"payerAuthentication": {
"referenceId": "<referenceId from 3DS setup response>",
"deviceInformation": {
"ipAddress": "203.0.113.42",
"httpAcceptBrowserValue": "text/html,application/xhtml+xml,*/*;q=0.8",
"httpAcceptContent": "text/html,application/xhtml+xml,*/*;q=0.8",
"httpBrowserLanguage": "en-US",
"httpBrowserJavaEnabled": false,
"httpBrowserJavaScriptEnabled": true,
"httpBrowserColorDepth": "24",
"httpBrowserScreenHeight": "1080",
"httpBrowserScreenWidth": "1920",
"httpBrowserTimeDifference": "-60",
"userAgentBrowserValue": "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) ..."
}
}
}
}
All deviceInformation fields are required. Missing fields cause a validation error.
Step 8 — Handle enrollment check response
Three outcomes are possible:
Outcome A — Frictionless (order placed immediately)
Centra places the order directly without any browser interaction. The response is a standard Centra order confirmation. No additional steps needed.
Outcome B — Challenge required (action: javascript)
The issuer requires the shopper to complete a challenge. Centra returns:
{
"action": "javascript",
"formFields": {
"authenticationTransactionId": "<UUID>",
"stepUpUrl": "<Cardinal Commerce step-up endpoint — use this value as-is>",
"stepUpAccessToken": "<JWT>",
"paReq": "<base64 payer auth request>"
}
}
Always use stepUpUrl exactly as returned — do not hardcode the Cardinal endpoint. Cybersource provides different hosts for sandbox (centinelapistag.cardinalcommerce.com) and production (centinelapi.cardinalcommerce.com).
Open the challenge in an iframe:
<iframe
id="step-up-iframe"
style="width: 400px; height: 400px;"
></iframe>
The `paReq` field is a base64-encoded JSON payload. Decoded, it contains a `challengeWindowSize` value that indicates the issuer's preferred iframe dimensions:
| `challengeWindowSize` | Width × Height |
|---|---|
| `01` | 250 × 400 |
| `02` | 390 × 400 |
| `03` | 500 × 600 |
| `04` | 600 × 400 |
| `05` | Full screen |
Use this value to size the iframe dynamically instead of hardcoding `400 × 400`.
<form
id="step-up-form"
target="step-up-iframe"
method="POST"
action="{stepUpUrl}"
>
<input type="hidden" name="JWT" value="{stepUpAccessToken}" />
</form>
// Store authenticationTransactionId for use in paymentResult
const { authenticationTransactionId } = formFields;
// Listen for challenge completion
window.addEventListener('message', (event) => {
let data;
try {
data = JSON.parse(event.data);
} catch {
return;
}
if (data.MessageType === 'customer.stepUpComplete') {
// Shopper completed the challenge — call paymentResult
completePayment(authenticationTransactionId, captureContext, transientToken);
}
});
document.getElementById('step-up-form').submit();
Outcome C — Authentication failed
Centra returns an error response (action: failed). Display the error to the shopper and allow them to retry or choose another payment method.
Step 9 — paymentResult (post-challenge only)
This step is only required after a 3DS challenge (Outcome B above). Call paymentResult to complete the authorization:
Storefront API:
mutation paymentResult($paymentMethodFields: Map!) {
paymentResult(paymentMethodFields: $paymentMethodFields) {
type
... on PaymentResultSuccessPayload {
order {
number
orderDate
status
totals {
type
price {
value
formattedValue
currency {
code
}
}
}
}
}
userErrors {
message
path
}
}
}
Variables:
{
"paymentMethodFields": {
"authenticationTransactionId": "<from challenge response formFields>",
"captureContext": "<captureContext JWT from paymentInstructions>",
"transientToken": "<transientToken JWT from Microform>"
}
}
All three fields are required. Missing any of them returns an error without attempting authorization.
What Centra returns (backend contract)
paymentInstructions — Capture Context
{
"action": "form",
"formType": "cybersource",
"formFields": {
"captureContext": "<short-lived JWT>"
}
}
Use captureContext to initialize Microform. Cybersource typically issues Capture Context JWTs with a 15-minute validity window — call paymentInstructions again if the shopper takes longer than that before submitting.
paymentSubmission — 3DS setup (action: javascript, first call)
Returned when 3DS is enabled and no payerAuthentication was present in the request:
{
"action": "javascript",
"formFields": {
"captureContext": "<captureContext JWT — echo from request>",
"transientToken": "<transientToken JWT — echo from request>",
"payerAuthentication": {
"accessToken": "<JWT — POST this to the DDC iframe as field 'JWT'>",
"deviceDataCollectionUrl": "<Cardinal Commerce DDC endpoint>",
"referenceId": "<UUID>"
}
}
}
The deviceDataCollectionUrl domain differs by environment:
| Environment | Domain |
|---|---|
| Sandbox | centinelapistag.cardinalcommerce.com |
| Production | centinelapi.cardinalcommerce.com |
Always use the URL as returned by Centra — do not hardcode it.
paymentSubmission — challenge required (action: javascript, second call)
Returned when the enrollment check determines the issuer requires a challenge:
{
"action": "javascript",
"formFields": {
"authenticationTransactionId": "<UUID>",
"stepUpUrl": "<Cardinal Commerce step-up endpoint>",
"stepUpAccessToken": "<JWT — POST this to the step-up iframe as field 'JWT'>",
"paReq": "<base64 encoded payer auth request>"
}
}
The stepUpUrl domain follows the same sandbox/production split as deviceDataCollectionUrl above.
paymentResult — required fields
| Field | Source |
|---|---|
authenticationTransactionId | From challenge response formFields |
captureContext | The JWT returned by paymentInstructions |
transientToken | The JWT generated by microform.createToken() |
Testing
Enable test mode
Set Test mode to Yes in the Centra admin. All Cybersource API calls will go to https://apitest.cybersource.com and Microform will load from https://testflex.cybersource.com.
In your frontend, detect test mode from the deviceDataCollectionUrl or stepUpUrl origins returned in the API responses — the sandbox uses cardinalcommerce.com domains for both environments, so confirm test mode routing through the Cybersource API hostname in your backend logs.
Load Microform from the sandbox URL in test mode
https://testflex.cybersource.com/microform/bundle/v2/flex-microform.min.js
Test cards
Use Cybersource's official test cards. Commonly used numbers for general authorization testing:
| Card number | Network | Expected result |
|---|---|---|
4111111111111111 | Visa | Successful authorization |
5555555555554444 | Mastercard | Successful authorization |
For 3DS-specific test scenarios (frictionless, challenge, authentication failure), refer directly to the Cybersource Payer Authentication testing guide — 3DS test card numbers are environment-specific and subject to change between sandbox versions.
Validate all flows
- Standard authorization — submit with
threeDSecurePreference: standard-authorizationand verify the order is placed in one round trip. - 3DS frictionless — complete device fingerprinting and verify the order is placed without a challenge window.
- 3DS challenge — complete device fingerprinting, open the challenge iframe, complete the simulated challenge, and verify
paymentResultplaces the order. - AVS decline handling — test with a card that triggers AVS decline; verify behavior with
ignore_avs_resultboth on and off. - Authentication failure — verify the frontend surfaces the error message and allows retry.