Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
75 changes: 44 additions & 31 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,76 +1,89 @@
# Accept Sample Application

The Accept sample application provides examples of how to use the Authorize.Net Accept suite of tools to integrate secure payment acceptance into your applications.

> ### ⚠️ Scope & Intended Use
>
> This repository is a **sample / educational application** — it is **not a product**, **not a hosted service**, and **not part of the main Authorize.Net product**. It is intended for developers who want to clone, host locally, and learn how the Accept suite (Accept.js, Accept Hosted, Accept Customer / Hosted CIM, Apple Pay on the Web) integrates against the Authorize.Net **sandbox**.
>
> - **Purpose:** Educational reference / integration showcase only.
> - **Deployment:** Designed to be hosted **locally** by each developer (IIS / XAMPP / Apache) over HTTPS. It is _not_ deployed to any hosted environment by Authorize.Net or Visa.
> - **Backend target:** Authorize.Net **Sandbox only** (`https://apitest.authorize.net`); Apple Pay **Sandbox only** (`apple-pay-gateway-cert.apple.com`). There is no production URL anywhere in the codebase.
> - **Data:** No database. State is per-PHP-process `$_SESSION` only.
> - **Credentials:** All Authorize.Net credentials come from per-developer-machine **environment variables** (`API_LOGIN_ID`, `TRANSACTION_KEY`, `PEM_PWD`, `DOMAIN_NAME`, `MERCHANT_ID`). The Accept.js public client key is replaced by the developer in `acceptJSCaller.js`. No real credentials ship in source.
>
> 📄 **Full security context, threat model, and AI SAST `poc_personal` validation guidance:** see [`SECURITY-CONTEXT.md`](./SECURITY-CONTEXT.md).

![Accept Screenshots](screenshots/AcceptTrioScreenShots.png "Screenshots showing the Accept hosted forms.")

## How to Use the Sample App

+ Clone or download this repository.
- Clone or download this repository.

+ Host the sample app in any web server supporting PHP, for example IIS or XAMPP (Apache). __HTTPS (SSL) must be enabled for your website.__
- Host the sample app in any web server supporting PHP, for example IIS or XAMPP (Apache). **HTTPS (SSL) must be enabled for your website.**

+ Set the authentication credentials in the application so that it uses your Authorize.Net sandbox (test) account. If you haven't yet signed up for a sandbox account, you can create a sandbox account at our [Developer Center] (https://developer.authorize.net/hello_world/sandbox/). Set environment variables for `API_LOGIN_ID` and `TRANSACTION_KEY` using the credentials for your Authorize.Net sandbox account. For example, in _httpd.conf_, you would add the following lines:
- Set the authentication credentials in the application so that it uses your Authorize.Net sandbox (test) account. If you haven't yet signed up for a sandbox account, you can create a sandbox account at our [Developer Center] (https://developer.authorize.net/hello_world/sandbox/). Set environment variables for `API_LOGIN_ID` and `TRANSACTION_KEY` using the credentials for your Authorize.Net sandbox account. For example, in _httpd.conf_, you would add the following lines:

SetEnv API_LOGIN_ID your_id
SetEnv TRANSACTION_KEY your_key
SetEnv TRANSACTION_KEY your_key

For IIS, you could set these environment variables in FastCGI Settings -> Environment Variables.

+ Set the authentication credentials that Accept.js uses. Edit the `acceptJSCaller()` function in _acceptJSCaller.js_ to use your API login ID and public client key for the values of `authData.apiLoginID` and `authData.clientKey`. A public client key can be created by logging into the [Merchant Interface](https://sandbox.authorize.net/) and navigating to __Account --> Security Settings --> Manage Public Client Key__.
- Set the authentication credentials that Accept.js uses. Edit the `acceptJSCaller()` function in _acceptJSCaller.js_ to use your API login ID and public client key for the values of `authData.apiLoginID` and `authData.clientKey`. A public client key can be created by logging into the [Merchant Interface](https://sandbox.authorize.net/) and navigating to **Account --> Security Settings --> Manage Public Client Key**.

+ Browse the application (_index.php_) over HTTPS connection.
- Browse the application (_index.php_) over HTTPS connection.

+ To "log in", use a customer profile ID that already exists within your account or create a new one by using the [Create a Customer Profile API](http://developer.authorize.net/api/reference/index.html#customer-profiles-create-customer-profile).
- To "log in", use a customer profile ID that already exists within your account or create a new one by using the [Create a Customer Profile API](http://developer.authorize.net/api/reference/index.html#customer-profiles-create-customer-profile).

+ In these examples, payment forms are shown in the same page and Shipping forms are handled in a separate modal popup. However, any of the types of display can be chosen to display any type of form.
- In these examples, payment forms are shown in the same page and Shipping forms are handled in a separate modal popup. However, any of the types of display can be chosen to display any type of form.

### Common issues during installation
1. **Error**: *Uncaught Error: Class 'SimpleXMLElement' not found in accept-sample-app/getToken.php:24*
+ **Possible methods to resolve** <br>
- Install simplexml package for your OS. Refer: http://stackoverflow.com/questions/35593521/php-7-simplexml
+ **Related issue** <br>
- https://github.com/AuthorizeNet/accept-sample-app/issues/25

1. **Error**: _Uncaught Error: Class 'SimpleXMLElement' not found in accept-sample-app/getToken.php:24_

- **Possible methods to resolve** <br> - Install simplexml package for your OS. Refer: http://stackoverflow.com/questions/35593521/php-7-simplexml
- **Related issue** <br> - https://github.com/AuthorizeNet/accept-sample-app/issues/25

## Included Examples

### Accept Customer
Accept Customer is the new name for Hosted CIM, part of our Customer Profiles API. See our [developer documentation](http://developer.authorize.net/api/reference/features/customer_profiles.html) for more details.

The sample application shows how to:
Accept Customer is the new name for Hosted CIM, part of our Customer Profiles API. See our [developer documentation](http://developer.authorize.net/api/reference/features/customer_profiles.html) for more details.

* Incorporate the Manage Customer hosted page into your application ("Profile" tab).
* Embed the hosted "Add/Edit Payment" page into your application as an iframe ("Payment Methods" tab).
* Pop up the hosted "Add/Edit Shipping" page in a light-box mode ("Shipping" tab).
The sample application shows how to:

- Incorporate the Manage Customer hosted page into your application ("Profile" tab).
- Embed the hosted "Add/Edit Payment" page into your application as an iframe ("Payment Methods" tab).
- Pop up the hosted "Add/Edit Shipping" page in a light-box mode ("Shipping" tab).

### Accept.js
Accept.js is a new integration option which allows you to leverage the full power of the Authorize.Net API while avoiding the PCI compliance burden of credit card information hitting your servers. See our [developer documentation](http://developer.authorize.net/api/reference/features/acceptjs.html) for more details.

The sample application shows how to:
Accept.js is a new integration option which allows you to leverage the full power of the Authorize.Net API while avoiding the PCI compliance burden of credit card information hitting your servers. See our [developer documentation](http://developer.authorize.net/api/reference/features/acceptjs.html) for more details.

* Incorporate the Accept.js library into your existing payment flow ("Pay" tab --> "Pay (Accept.js)" button)
The sample application shows how to:

- Incorporate the Accept.js library into your existing payment flow ("Pay" tab --> "Pay (Accept.js)" button)

### Accept Hosted
Accept Hosted provides a fully hosted payment transaction solution. Authorize.Net takes care of the payment form, the transaction itself, and the receipt generation (optional). We have a Step-by-Step guide to the sample implementation here: [README-AcceptHosted.md](README-AcceptHosted.md). See our [developer documentation](http://developer.authorize.net/api/reference/features/accept_hosted.html) for more details.

The sample application shows how to:
Accept Hosted provides a fully hosted payment transaction solution. Authorize.Net takes care of the payment form, the transaction itself, and the receipt generation (optional). We have a Step-by-Step guide to the sample implementation here: [README-AcceptHosted.md](README-AcceptHosted.md). See our [developer documentation](http://developer.authorize.net/api/reference/features/accept_hosted.html) for more details.

* Request an Accept Hosted form token using the Authorize.Net API (GetHostedPaymentForm).
* Incorporate the Accept Hosted payment form into your existing payment flow ("Pay" tab).
* Display a custom receipt using the transaction response.
The sample application shows how to:

- Request an Accept Hosted form token using the Authorize.Net API (GetHostedPaymentForm).
- Incorporate the Accept Hosted payment form into your existing payment flow ("Pay" tab).
- Display a custom receipt using the transaction response.

### Apple Pay On The Web
Authorize.Net supports Apple Pay on the Web in addition to our in-app Apple Pay Support. See our [developer documentation](http://developer.authorize.net/api/reference/features/in-app.html) for more details.

Authorize.Net supports Apple Pay on the Web in addition to our in-app Apple Pay Support. See our [developer documentation](http://developer.authorize.net/api/reference/features/in-app.html) for more details.

![Apple Pay Screenshot](screenshots/apple-pay.png "Screenshots showing Apple Pay on the Web.")

In this sample we demonstrate how to:
In this sample we demonstrate how to:

* Integrate with the ApplePay.js library.
* Validate your merchant identity from your server.
* Complete the transaction by passing the Apple Pay payment data in the Authorize.Net `createTransactionRequest` API call.
- Integrate with the ApplePay.js library.
- Validate your merchant identity from your server.
- Complete the transaction by passing the Apple Pay payment data in the Authorize.Net `createTransactionRequest` API call.

Please note that you will need to have a merchant ID set up with Apple as described in their [Apple Pay documentation](https://developer.apple.com/reference/applepayjs/).
203 changes: 110 additions & 93 deletions acceptJSCaller.js
Original file line number Diff line number Diff line change
@@ -1,114 +1,131 @@
// The result of the transaction processing will be returned from the processing script as a JSON object. Parse the object to determine success or failure, and alert the user.
function messageFunc(msg)
{
try{
responseObj=JSON.parse(msg);
if(responseObj.transactionResponse.responseCode=='1'){
message="Transaction Successful!<br>Transaction ID: "+responseObj.transactionResponse.transId;
}
else{
message="Transaction Unsuccessful.";//+responseObj.messages.message[0].text;
if(responseObj.transactionResponse.errors!=null)//to do: take care of errors[1] array being parsed into single object
{
message+=responseObj.transactionResponse.errors.error.errorText;
}
/*else if(responseObj.transactionResponse.errors[0]!=null)
function messageFunc(msg) {
try {
responseObj = JSON.parse(msg);
if (responseObj.transactionResponse.responseCode == "1") {
message =
"Transaction Successful!<br>Transaction ID: " +
responseObj.transactionResponse.transId;
} else {
message = "Transaction Unsuccessful."; //+responseObj.messages.message[0].text;
if (
responseObj.transactionResponse.errors != null
) //to do: take care of errors[1] array being parsed into single object
{
message += responseObj.transactionResponse.errors.error.errorText;
}
/*else if(responseObj.transactionResponse.errors[0]!=null)
{
for(i=0;i<responseObj.transactionResponse.errors.length;i++)
{
message+="<br>";
message+=responseObj.transactionResponse.errors[i].error.errorText;
}
}*/
if(responseObj.transactionResponse.transId!=null)
{
message+="<br>";
message+=("Transaction ID: "+responseObj.transactionResponse.transId)
}
}
}
catch(error){
console.log("Couldn't parse result string");
message="Error.";
}

//alert(message);

$('#acceptJSReceiptBody').html(message);
//jQuery.noConflict();
$('#acceptJSPayModal').modal('hide');
$('#acceptJSReceiptModal').modal('show');
if (responseObj.transactionResponse.transId != null) {
message += "<br>";
message += "Transaction ID: " + responseObj.transactionResponse.transId;
}
}
} catch (error) {
console.log("Couldn't parse result string");
message = "Error.";
}

//alert(message);

$("#acceptJSReceiptBody").html(message);
//jQuery.noConflict();
$("#acceptJSPayModal").modal("hide");
$("#acceptJSReceiptModal").modal("show");
}

// Do an AJAX call to submit the transaction data and the payment none to a separate PHP page to do the actual transaction processing.
function createTransact(dataObj) {
// Set Amount for demo purposes if not set by callers form
myAmt = document.getElementById('amount').value;
if(!myAmt)
{
myAmt = Math.floor((Math.random() * 100) + 1);
}
console.log('Amount = '+myAmt);
$.ajax({
url: "transactionCaller.php",
data: {amount: myAmt, dataDesc: dataObj.dataDescriptor, dataValue: dataObj.dataValue},
method: 'POST',
timeout: 5000
}).done(function(data){
console.log('Success');
}).fail(function(){
console.log('Error');
}).always(function(textStatus){
console.log(textStatus);
messageFunc(textStatus);
})
// Set Amount for demo purposes if not set by callers form
myAmt = document.getElementById("amount").value;
if (!myAmt) {
myAmt = Math.floor(Math.random() * 100 + 1);
}
console.log("Amount = " + myAmt);

// Security: Get CSRF token from hidden input
var csrfToken = $("#csrfToken").val();

$.ajax({
url: "transactionCaller.php",
data: {
amount: myAmt,
dataDesc: dataObj.dataDescriptor,
dataValue: dataObj.dataValue,
csrf_token: csrfToken, // Security: Include CSRF token
},
method: "POST",
timeout: 5000,
})
.done(function (data) {
console.log("Success");
})
.fail(function () {
console.log("Error");
})
.always(function (textStatus) {
console.log(textStatus);
messageFunc(textStatus);
});
}

// Process the response from Authorize.Net to retrieve the two elements of the payment nonce.
// If the data looks correct, record the OpaqueData to the console and call the transaction processing function.
function responseHandler(response) {
if (response.messages.resultCode === 'Error') {
for (var i = 0; i < response.messages.message.length; i++) {
console.log(response.messages.message[i].code + ':' + response.messages.message[i].text);
}
alert("acceptJS library error!")
} else {
console.log(response.opaqueData.dataDescriptor);
console.log(response.opaqueData.dataValue);
createTransact(response.opaqueData);
}
function responseHandler(response) {
if (response.messages.resultCode === "Error") {
for (var i = 0; i < response.messages.message.length; i++) {
console.log(
response.messages.message[i].code +
":" +
response.messages.message[i].text,
);
}
alert("acceptJS library error!");
} else {
console.log(response.opaqueData.dataDescriptor);
console.log(response.opaqueData.dataValue);
createTransact(response.opaqueData);
}
}

function acceptJSCaller()
{
var secureData = {} , authData = {} , cardData = {};

// Extract the card number and expiration date.
cardData.cardNumber = document.getElementById('creditCardNumber').value;
cardData.cardCode = document.getElementById('cvv').value;
cardData.month = document.getElementById('expiryDateMM').value;
cardData.year = document.getElementById('expiryDateYY').value;
secureData.cardData = cardData;
function acceptJSCaller() {
var secureData = {},
authData = {},
cardData = {};

// Extract the card number and expiration date.
cardData.cardNumber = document.getElementById("creditCardNumber").value;
cardData.cardCode = document.getElementById("cvv").value;
cardData.month = document.getElementById("expiryDateMM").value;
cardData.year = document.getElementById("expiryDateYY").value;
secureData.cardData = cardData;

// The Authorize.Net Client Key is used in place of the traditional Transaction Key. The Transaction Key
// is a shared secret and must never be exposed. The Client Key is a public key suitable for use where
// someone outside the merchant might see it.
// SAMPLE ONLY:
// `apiLoginID` is a non-secret merchant identifier (NOT a credential like
// `Transaction Key`). `clientKey` is the Authorize.Net Public Client Key —
// it is designed to be exposed to the browser; it can ONLY be used by the
// issuing merchant's own Accept.js flow to mint single-use, short-lived
// opaque tokens for that merchant's own card data.
//
// Per README, each developer must replace these placeholders with their
// own per-developer sandbox values. Generate them in the Authorize.Net
// Sandbox Merchant Interface → Account → Security Settings →
// - "API Credentials & Keys" for the apiLoginID
// - "Manage Public Client Key" for the clientKey
//
// The shared-secret `Transaction Key` (which IS a credential) lives only
// in your server-side env-vars (`getenv("TRANSACTION_KEY")` in
// transactionCaller.php) and is never sent to the browser.
authData.clientKey = "[YOUR_PUBLIC_CLIENT_KEY]";
authData.apiLoginID = "[YOUR_API_LOGIN_ID]";
secureData.authData = authData;

authData.clientKey = '6jZy4G5vmCEat9G3xjtNguj7DLw5NhgS4PBr4KNp7tV2tXa34E3BkdG33dcX4S84';
authData.apiLoginID = '3e3b5H4YLP';
secureData.authData = authData;

// Pass the card number and expiration date to Accept.js for submission to Authorize.Net.
Accept.dispatchData(secureData, 'responseHandler');
// Pass the card number and expiration date to Accept.js for submission to Authorize.Net.
Accept.dispatchData(secureData, "responseHandler");
}
Loading