Danielle M.
12 min readMar 7, 2019

It’s long, but if you follow my method, it will work like a charm! :)

Building Stripe Payment with React.js (Easy and full implementation directions for react.js frontend and node.js & express backend deployment on Digital Ocean)

I spent three hours this morning looking for a full, simple, and easy guideline that integrates Stripe payment solutions with React.js seamlessly.

There are all small puzzles of a big picture. Those posts suggest you to use this and do that. “Sounds good, doesn’t work!” :) So I decided to write one!

Let me share a conclusive Stripe payment guide targeted for React.js single page app (SPA). This guide should cover from the beginning to the end. It includes frontend and backend.

Index:

  1. Setup the Stripe account (you can do the plugin testing just based on test account)
  2. Set up Stripe frontend
  3. Set up Stripe backend
  4. Deploy your backend using Digital Ocean
  5. Deploy your frontend (I wouldn’t talk about this since we all have different preference over how to deploy our React SPA

Before going into detail, let me briefly explain how Stripe payment system works. This is how user workflow goes:

  1. A user goes to buy or checkout page. Clicks “Pay with Card” button.
  2. A Stripe checkout button comes pops up, asking users to plug in the credit card number, expiration date, CVC, zipcode, and email.
  3. Once, a user clicks “pay” button, the credit card information is encrypted in a token (encrypted with public key). The credit card token is sent and saved in Stripe database.
  4. Once confirmed, stripe sends you back with the encrypted token ID (for your transaction tracking).
  5. Once Stripe sends your user browser a token for credit card verification, you will have to ping your backend server to post charges to stripe database. This time, this charges are encrypted with your secret key.
  6. Once Stripe server receives the charges from your node.js backend(many other options available), the transaction gets posted successfully.

It’s a two factor authentication to ensure the payment information are not compromised. It sounds hard, but it’s actually quite easy. If you are brand new to this process, this process should take somewhere between 2–3 hours.

1. Setting up a Stripe account

We will be using Stripe checkout account. Once you set everything up (even without providing your actual bank account and payment information), you will get following API keys.

There are two keys:

  1. Publishable key — the publishable key will go on your front end code. The key usually starts with “pk.”
  2. Secret key — the secret key will go to your backend code. The key usually starts with “sk.”

Please note that there are different PKs and SKs for test environments and production environments.

Once you set up your Stripe account, let’s go ahead and blow up the front-end.

2. Setting up the Frontend Code

For front end code, we will use following three frameworks.

  1. Create React app
  2. Axios (to ping your own node.js backend server)
  3. React-stripe-checkout

Let’s get it going.

You make a new directory and get there:

mkdir react-stripe-testcd react-stripe-test

Let’s install create-react-app (I am sure most of us have it, but just in case)

npm install -g create-react-app

Create a react app with create-react-app above and get in there

create-react-app frontendcd frontend

Once you get in there, you will see bunch of files have been set up with create react app. Now, let’s install Axios and react-stripe-checkout

npm install axios react-stripe-checkout

Now, the skeleton is ready. Let’s create couple more files to get this going.

Let’s get into source directory (src) which has all javascript files.

cd srctouch Checkout.js

After that, let’s create a subfolder with constants and create server.js and stripe.js

mkdir constants && cd constantstouch server.js stripe.js

Now, go back to src directory, go to src/App.js file (the index jsx file) and add following code

import React, { Component } from 'react';
import logo from './logo.svg';
import Checkout from './Checkout';
import './App.css';

class App extends Component {
render() {
return (
<div className="App">
<div className="App-header">
<img src={logo} className="App-logo" alt="logo" />
<h2>Welcome to React</h2>
</div>
<p className="App-intro">
<Checkout
name={'Your Company Name'}
description={'Item that you sold'}
amount={4.99}

/>
</p>
</div>
);
}
}

export default App;

Explanation: You import <Checkout/> Module from checkout (see below). You pass the variable, such as, your company name, item purchase, and amount to process.

Do you see the highlighted part? The highlighted part will be the shown for your customer’s credit card statement. You don’t want to say something weird here because that will increase your chargeback or dispute ratio. Keep it simple and easy, so that you and your customers are both on the same page!

Now, go to checkout.js file on the same page (src/checkout.js) and add following code

import React from 'react'
import axios from 'axios';
import StripeCheckout from 'react-stripe-checkout';

import STRIPE_PUBLISHABLE from './constants/stripe';
import PAYMENT_SERVER_URL from './constants/server';

const CURRENCY = 'USD';

const fromDollarToCent = amount =>
parseInt(amount * 100);

const successPayment = data => {
alert('Payment Successful');
};

const errorPayment = data => {
alert('Payment Error');
};

const onToken = (amount, description) => token =>
axios.post(PAYMENT_SERVER_URL,
{
description,
source: token.id,
currency: CURRENCY,
amount: fromEuroToCent(amount)
})
.then(successPayment)
.catch(errorPayment);

const Checkout = ({ name, description, amount }) =>
<StripeCheckout
name={name}
description={description}
amount={fromDollarToCent(amount)}
token={onToken(amount, description)}
currency={CURRENCY}
stripeKey={YOUR_STRIPE_PUBLISHABLE_KEY}
zipCode
email
allowRememberMe

/>

export default Checkout;

Explanation: Once, user clicks checkout button from page above, the data is submitted via StripeCheckout. Once credit card information is sent, it will give you a TOKEN_ID back. You will pick that TOKEN and ping to your node.js (express) backend server via Axios. Your backend will post the payment to the Stripe (which is shown on step 3).

Couple of notes on highlighted thing:

  1. You nominate your own currency that you wanna charge. Here, we are going to charge USD.
  2. You multiply the number by 100 and convert it back to the closet integer. Stripe takes in by the cents. So, if you want to charge USD 4.99, you will have to charge 499 USD. That will automatically get recorded as USD 4.99.
  3. The bottom parts are the items that you want to get from your customers. You want your client to plug in zipcode, email, and allow them to remember you (so that they don’t have to type in credit card numbers when they do second purchase from you).
  4. on Stripe key above, make sure you plug in your publishable key starting with PK.

Now, go into the constants directory and past following codes on server.js file (src/constants/server.js)

const PAYMENT_SERVER_URL = process.env.NODE_ENV === 'production'
? 'http://myapidomain.com'
: '
http://localhost:8080';

export default PAYMENT_SERVER_URL;

Explanation: Designating which server to call. When you are in production mode, your server will be IP address on digital ocean — look a bottom section. For development environment, we will be using localhost port 8080.

Here, we will be using localhost:8080 as your test port for your backend server. If you wanna use port 5000, then adjust your port to http://localhost:5000. Make sure it’s http instead of https.

For your production address, we will put the backend server address (from digital ocean) later.

Now, go into the constants directory and past following codes on stripe.js file ( src/constants/stripe.js)

const STRIPE_PUBLISHABLE = process.env.NODE_ENV === 'production'
? 'pk_live_MY_PUBLISHABLE_KEY'
: 'pk_test_MY_PUBLISHABLE_KEY';


export default STRIPE_PUBLISHABLE;

Explanation: We are adding keys.

On Stripe key above, make sure you plug in your publishable key starting with PK. Make sure you give one for your production environment (live) and testing environment (test). They are both located on your Stripe dashboard.

Believe or not, that’s it for the front end. Go back to your frontend directory (~/frontend) and start your server.

cd ~/Frontend
npm start

Your sever will start, and you will see following screen.

Click pay with card, you will see following

Once you plug in test credit card info, “4242 4242 4242 4242”, “11/25”, “001”, you will see the “Transaction failed notification.”

  • It will be successful, once we have the backend up and running :)

3. Now, let’s set up the backend

Now, we set up the backend

Go back to the original directory and create backend directory.

cd ~/react-stripe-testmkdir backend && cd backend

Once you get to the backend directory, now we will install Express, Cors, body-parser and stripe.

npm init-ynpm install --save body-parser cors express stripe

Once, the installation is done, we create two files on the same directory.

touch index.js and server.js

Once that’s done, we create two directories: constants and routes

mkdir constants routes

Go into constants directory and create frontend.js, server.js, and stripe.s

cd constantstouch frontend.js server.js stripe.js

Now, you get out of the constants directory, and create index.js and payment.js files on routes directory.

cd ..cd routestouch index.js payment.js

Now, go back to the original directory and past folowing coes on ~/backend/index.js file

const express = require('express');

const SERVER_CONFIGS = require('./constants/server');

const configureServer = require('./server');
const configureRoutes = require('./routes');

const app = express();

configureServer(app);
configureRoutes(app);

app.listen(SERVER_CONFIGS.PORT, error => {
if (error) throw error;
console.log('Server running on port: ' + SERVER_CONFIGS.PORT);
});

Explanation: This code is configuring your backend server setup.

On backend/constants/frontend.js file, you add following code:

const FRONTEND_DEV_URLS = [ 'http://localhost:3000' ];

const FRONTEND_PROD_URLS = [
'https://www.yourdomain.com',
'
https://yourdomain.com'
];

module.exports = process.env.NODE_ENV === 'production'
? FRONTEND_PROD_URLS
: FRONTEND_DEV_URLS;

Explanation: Restricting which server can be used to ping your backend. You don’t want random attacker to ping your DB.

Please make sure updated the highlighted part — the test url and production url for frontend.

Now, go to constants/server.js and add following code:

const path = require('path');

const SERVER_PORT = 8080;

const SERVER_CONFIGS = {
PRODUCTION: process.env.NODE_ENV === 'production',
PORT: process.env.PORT || SERVER_PORT,
};

module.exports = SERVER_CONFIGS;

Make sure your backend port number is correct. We will be launching our backend server on http://localhost:8080 (port 8080).

Now, go to stripe.js and add following code:

const configureStripe = require('stripe');

const STRIPE_SECRET_KEY = process.env.NODE_ENV === 'production'
? 'sk_live_MY_SECRET_KEY'
: 'sk_test_MY_SECRET_KEY';

const stripe = configureStripe(STRIPE_SECRET_KEY);

module.exports = stripe;

Explanation: Defining your secret key

This directory contains the stripe credentials. Please update the highlighted part with your secret keys. This part will be remain confidential in the backend. Don’t share these keys with anyone.

Go to server.js and add following code:

const cors = require('cors');
const bodyParser = require('body-parser');

const CORS_WHITELIST = require('./constants/frontend');

const corsOptions = {
origin: (origin, callback) =>
(CORS_WHITELIST.indexOf(origin) !== -1)
? callback(null, true)
: callback(new Error('Not allowed by CORS'))
};

const configureServer = app => {
app.use(cors(corsOptions));

app.use(bodyParser.json());
};

module.exports = configureServer;

Explanation: Once, you pass the CORS inbound text (whitelisted websites — which is your frontend address), user bodyparer to parse out JSON details that you receive.

Now, go to routes/payment.js file and add following code

const stripe = require('../constants/stripe');

const postStripeCharge = res => (stripeErr, stripeRes) => {
if (stripeErr) {
res.status(500).send({ error: stripeErr });
} else {
res.status(200).send({ success: stripeRes });
}
}

const paymentApi = app => {
app.get('/', (req, res) => {
res.send({ message: 'Hello Stripe checkout server!', timestamp: new Date().toISOString() })
});

app.post('/', (req, res) => {
stripe.charges.create(req.body, postStripeCharge(res));
});

return app;
};

module.exports = paymentApi;

Explanation: If Stripe receives your data, it sends 200 (OK). If 500, it’s not okay, It will show the payment has NOT been successful in case of 500.

Now, go to routes/index.js file and add following code

const paymentApi = require('./payment');

const configureRoutes = app => {
paymentApi(app);
};

module.exports = configureRoutes;

Explanation: Running the payment API

We are done with the backend. Now go back to the backend’s root directory and start server.

cd ~/backendnode index.js

You will see your server starting.

Make sure you both get the port 3000 (frontend) and 8080 (backend) running and process the payment (with credit card number 4242 4242 4242 4242) and you will see your transcation get posted.

On Stripe dashboard, you should see following

One transaction should post token and the next will pot charge. This two process needs to be done to successfully take a payment. With token only, you will not get paid!

4. Not it’s the last step — Let’s deploy your backend app to the production environment.

I have considered a lot of options. The best one is digital ocean. I think it’s cheaper than anything else and the server will be running 24/7. It’s only $5 a month.

Let’s go to Digital Ocean and sign up for a droplet account.

Step 1: Create a New project.

Step 2: Skip the moving part and create a new droplet

Step 3: Select options

Select Ubuntu, Standard, and $5 plan

Now you will see your droplet and IP Address (blurred out on purpose. You will need this later). Make sure you get your IP address :)

Now you are going to access your Digital Ocean virtual machine from your desktop:

ssh root@SERVER_IP_ADDRESS

Remember your IP address mentioned on step above? Time to put this on.

Log on. They will ask for your password. Your initial password to your virtual machine has been sent from Digital Ocean on your email. Check your mailbox, if not, reset the password from dashboard.

Go to access section and rest password (ONLY IF YOU DON’T Have the password). Your new password will be sent to your email.

Enter your new password and confirm it. The cursor will not be moving when you type. Just be confident and type it. It should be something easy to memorize.

Now your create a new user named authorizedUser. You can name whatever you’d like.

adduser authorizedUser

Now, create admin privilege

usermod -aG sudo authorizedUser

Setting up SSH key for the new user

From your LOCAL machine, you enter following code

cat ~/.ssh/id_rsa.pub

This will print your SSH key to the terminal, which you can then copy.

From your ROOT machine (second terminal), you enter following code.

su - meziemkdir ~/.sshchmod 700 ~/.sshtouch ~/.ssh/authorized_keysvim ~/.ssh/authorized_keys

Now paste your SSH key above and paste on vim.

Once you are done, hit ESC and enter :wq to exit.

chmod 600 ~/.ssh/authorized_keysexit

Now go back to the virtual machine from your local computer to clone the node js backend app on your server. Remeber to ender the server IP address.

ssh mezie@SERVER_IP_ADDRESS

You will be asked to enter your newly entered password.

Once you are in the virtual machine, update it with your github code.

git clone your_git_hub_http_code mine is https://github.com/wrhong7/easyStripeDeployment.git

Next, we will install dependencies on Digital Ocean’s virtual machine

cd react-stripe-testnpm installsudo npm install -g pm2

Once PM2 is installed, we will startup PM@

pm2 startup systemd

You will get following command:

[PM2] Init System found: systemd
[PM2] To setup the Startup Script, copy/paste the following command:
sudo env PATH=$PATH:/usr/local/bin /usr/local/lib/node_modules/pm2/bin/pm2 startup systemd -u authorizedUser --hp /home/authorizedUser

Copy the highlighted last command and run the last command. Now the PM2 will boot up.

We will install Nginx now. Nginx is used for the reverse proxy, which will allow us to directly access the application from your IP port.

sudo apt-get updatesudo apt-get install nginxsudo ufw allow 'Nginx HTTP'

Once that’s done, we will have to set up Nigix for our reverse proxy

sudo vim /etc/nginx/sites-available/default

You will get another vim edit lines

Enter E for edit anyway.

Add the highlighted code below on the location section


location / {
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header X-NginX-Proxy true;
proxy_pass http://localhost:3000;
proxy_set_header Host $http_host;
proxy_cache_bypass $http_upgrade;
proxy_redirect off;
}

Now paste your SSH key above and paste on vim.

Once you are done, hit ESC and enter :wq to exit.

Now, exit the vim and let’s run it.

sudo nginx -tsudo systemctl restart nginx

WE ARE DONE! EXCEPT ONE!

Go to frontend/src/constants/server.js and update the pinging backend address with your new IP production address.

Update with your new IP address and DON’T FORGET PORT 8080.

That’s it! Your app should be running smoothly now!

Click here to check out how Stripe is helping me to charge right amount to our clients.