Integrate Stripe Payment Gateway in Ionic 5 apps and PWA using Firebase
Stripe is one of the most widely used and fastest-growing payment gateway which you can integrate into your website or app. It supports a wide variety of payment options and is quickly spreading across the globe. Stripe can take care of almost all your payment requirements in apps and websites. Stripe’s ease of integration has made it a popular developer choice over PayPal and other payment gateways. A good comparison between Stripe and PayPal can be studied here (spoiler — Stripe wins)
What is Ionic 5?
You probably already know about Ionic, but I’m putting it here just for the sake of beginners. Ionic is a complete open-source SDK for hybrid mobile app development created by Max Lynch, Ben Sperry and Adam Bradley of Drifty Co. in 2013. Ionic provides tools and services for developing hybrid mobile apps using Web technologies like CSS, HTML5, and Sass. Apps can be built with these Web technologies and then distributed through native app stores to be installed on devices by leveraging Cordova.
So, in other words — If you create Native apps in Android, you code in Java. If you create Native apps in iOS, you code in Obj-C or Swift. Both of these are powerful but complex languages. With Cordova (and Ionic) you can write a single piece of code for your app that can run on both iOS and Android (and Windows ! ), that too with the simplicity of HTML, CSS, and JS.
Ionic 5 and Payment Gateways
Ionic 5 can create a wide variety of apps, and hence a wide variety of payment gateways can be implemented in Ionic 5 apps. The popular ones are PayPal, Stripe, Braintree, in-app purchases, etc. For more details on payment gateways, you can read the blog on Payment Gateway Solutions in Ionic 5.
Stripe can be integrated into websites as well as mobile apps. There are different ways of integration of Stripe SDK. In this blog, we’ll learn how to integrate Stripe payment gateway in Ionic 5 apps and Ionic 5 PWA.
There are two main ways of integrating Stripe into an Ionic application.
You can either go with the Ionic Native implementation, which is a wrapper around the Stripe native SDKs for iOS and Android. This is powered by Cordova-plugin-stripe. This has the limitation of only facilitating the creation of tokens for once off payments. This works for both the mobile app and PWA.
The alternative approach is to use Stripe.js which is Stripe’s JavaScript implementation of their functionality. This is easy to use and quick to implement as this is implemented in JavaScript. The functionality is delivered dynamically into the page and supports both single and recurring payments. Again, you can use it both in mobile and Web, but here we’ll see a web implementation only.
In this post, we will learn how to implement both these methods for Stripe payments in an Ionic 5 app and PWA. To simplify the understanding, let us understand the complete flow pictorially
Let us start with prerequisites first
- Create an Ionic 5 app for Stripe integration
- Stripe Developer account for API keys
Prerequisites
Create a basic Ionic 5 app
Creating a basic Ionic 5 app is very easy. Assuming you have all the basic requirements installed in your system, run
$ ionic start MyApp sidemenu
This creates your app with the title MyApp
and side menu template.
For more details on how to create a basic Ionic 5 app, refer to my blog How to create an Ionic 5 app
With minor modifications, my homepage looks like this.
The file structure looks something like this, just for an idea
The main functional part of this HTML is nothing but the payment button you see above, which invokes payWithStripe()
function
<ion-button expand="full" color="success" (click)="payWithStripe()">Pay with Stripe</ion-button>
Stripe Developer Account for API keys
Visit Stripe.com and create an account. Stripe payment services are currently available in limited countries as shown on this page.
Once you are inside the Stripe Dashboard, look for the Developer Tab -> API keys.
Publishable key is what you use for connecting the Strive Native SDK or Stripe.js in front-end. Secret key is used in the back-end, where your server connects with Stripe’s server for actual payment.
That’s all you need from the Stripe account, for now. You can toggle the Live keys and use them instead once you have tested the process.
Let’s look into the Ionic 5 integration of Stripe now.
It has the following 4 steps:
- Step 1 — Integrate Stripe Native plugin (SDK) for token generation at the app level
- Step 2 — Integrate Stripe JS in your PWA / website for token generation at the website level
- Step 3 — Create Firebase function (or any back-end function to accept API calls) to accept tokens from the app, and make payment requests to the Stripe server
- Step 4 — Connect app / PWA to our Firebase server. Complete Stripe payment requests from the Firebase server.
Let’s start step-by-step
Step 1 — Integrate Stripe Native plugin
Please note that both Step 1 and Step 2 mentioned above only help you create a payment token from Stripe server. It DOES NOT complete a payment. To complete the payment, you can use the generate token, send it to your server, and complete the payment request via your server (Step 4 below)
To include Stripe functionality in your Ionic 5 app, you need to install a Stripe native plugin. Install the plugin with the following commands
$ ionic cordova plugin add cordova-plugin-stripe
$ npm install @ionic-native/stripe
After installation completes, import the Stripe module in your app.module.ts
and also import Stripe in your stripe.page.ts
page file, like so
Now, with native SDK, we can only generate a payment token for one-off payments via Stripe SDK. The payment function looks like the following
setPublishableKey
connects Stripe SDK using your publishable key.
createCardToken
along with card details, create a card in Stripe. You can apply front-end checks on card details, otherwise, Stripe server will send a relevant error message.
Note that the card details used here are Stripe’s default test card details. You can find more test cards in Stripe’s docs
In a successful response to createCardToken
function, the Stripe server will send back a payment token. This is the extent of the functionality of Stripe’s Ionic Native plugin for now. We’ll see in Step 3 & 4 how to use this token to complete a payment request.
Note:
Stripe Native plugin works for both the mobile app and PWA. For testing PWA implementation, create a browser platform for the app
$ ionic cordova platform add browser
Once the platform is added, run
$ ionic cordova run browser
and you can test the implementation of Stripe Native plugin in PWA.
Step 2 — Integrate Stripe.js in your PWA / website
In this part, we’ll integrate Stripe in a PWA / website environment, since the native plugin will not work here. Our PWA/website page in the sample repo looks like following
First of all, add stripe.js
to your index.html
file. This is valid for both if you are creating an Ionic 5 PWA or a standalone website.
<script src="https://js.stripe.com/v3/" async></script>
With stripe.js
we use what is called Stripe Elements, which is similar to PayPal’s Payment Button. With Stripe Elements, you get a ready-made payment form, with proper validations, localizations, and in-browser payment support.
We will implement the stripe.js
elements in a separate page in our Ionic 5 app — Stripe-web.
In the HTML page, instead of a normal button, we create a form that integrates Stripe elements.
Notice the payment-form
, card-element
and card-errors
ID elements, which will be used by Stripe elements.
payment-form
will contain the form, listeners for inputs and submit button, card-element
will contain the card-input form and card-errors
will show any validation errors. The styling for these divs can be controlled easily.
Now the JS implementation. The logic part of the Stripe element will look like the following.
Let’s walk through it one step at a time
We import Stripe in the page with
declare var Stripe;
and then creating stripe
variable
stripe = Stripe('YOUR_PUBLISHABLE_KEY');
This is the initialization step of Stripe elements on your page. Now, since we need the HTML divs to create Stripe elements, we’ll call the relevant functions in ngOnInit
so all HTML elements are loaded beforehand.
ngOnInit() { this.setupStripe(); }
Now, the setupStripe
the function contains all the implementation parts of Stripe.js functionality. First of all, we create card
in the HTML div with the IDcard-element
let elements = this.stripe.elements(); var style = { base: { color: '#32325d', lineHeight: '24px', fontFamily: '"Helvetica Neue", Helvetica, sans-serif', fontSmoothing: 'antialiased', fontSize: '16px', '::placeholder': { color: '#aab7c4' } }, invalid: { color: '#fa755a', iconColor: '#fa755a' } }; this.card = elements.create('card', { style: style }); console.log(this.card); this.card.mount('#card-element');
This creates the card input form in HTML which contains four parts
- Card number
- Expiry Date
- CVC, and
- ZIP
All validations are handled automatically, so that’s a 😅
Next, we attach listeners to form-inputs for displaying validation errors in the HTML div with ID card-errors
, if any
this.card.addEventListener('change', event => { var displayError = document.getElementById('card-errors'); if (event.error) { displayError.textContent = event.error.message; } else { displayError.textContent = ''; } });
Finally, we listen to the submit
event of the form, to submit the tokenization request to Stripe server
var form = document.getElementById('payment-form'); form.addEventListener('submit', event => { event.preventDefault();
this.stripe.createSource(this.card).then(result => { if (result.error) { var errorElement = document.getElementById('card-errors'); errorElement.textContent = result.error.message; } else { console.log(result); } }); });
Notice the createSource
function, that creates a payment token. We discussed earlier that the Native SDK can only generate tokens for one-off payments, but here you can generate tokens for cards, from which you can make repeat payments as well. Use createToken() if you need to make a once-off payment or createSource() to create a card that can be billed multiple times in the future.
The result returns a lot of useful info, that can be stored locally, stored on the server or can be just used once to create payments, using the returned token.
Notice the usage: reusable
denotes multiple transactions that can be done on this card i.e. subscription payments etc.
With this, we have successfully created tokens using Stripe elements (stripe.js) in PWA / website environment.
Step 3 — Creating Firebase project, functions and Node Express server to execute API calls to Stripe server
First two steps of Stripe integration allowed us to generate payment tokens in an app and website environment. But tokens aren’t payments. We want to complete a payment using Stripe. This is where Stripe is a little different from PayPal. PayPal allows you to do the complete payment on the front-end itself, while Stripe only allows payments from the back-end.
For example purpose, we will use Firebase back-end and nodejs Express REST APIs, since it is the easiest to implement with an Ionic 5 app. At first, Once the Firebase project is setup, we’ll make a simple HTTP request to our Firebase server for payment completion.
Connect Firebase to your project
In short, you can create a Firebase Project on the Firebase console webpage, connect it to the Ionic 5 app using firebase init
. Also, for this, you need to have firebase-tools installed in your system. (Use npm install firebase-tools -g
)
Once you have your project ready, connect it to your Ionic 5 app using
$ firebase init
then choosing the project, and choosing functions
option from the choices.
With Firebase Functions, you can essentially write back-end functions in the same environment, test locally with firebase serve
and can then deploy these to your Firebase project, so it can be connected to your app / website.
Once you have the Firebase project connected, you will see a functions
folder in your project root, as shown below
Create a firebase function to make payment requests
After this, you can create your back-end function in functions/index.js
file. This function will accept a request object from your app/website, send the payment request to the Stripe server, and return the response to your app/website again.
Notice that the payment request from your app should contain
- amount — in number (Notice: this number is in cents when you use “USD”. So use 100 if the payment is for $1. Using less than 50 will give an error.)
- currency — currency code string e.g. “USD”
- token — the one we received in Step 1 and Step 2
This data should be sent in an object in the POST API request, shown in the next step.
Test Firebase functions locally
To test whether your Firebase function is correctly written, run the function locally by running the command
$ firebase serve
This will start your firebase local server, and the URL will be displayed in the terminal, something like
http://localhost:5000/shoppr-c97a7/us-central1/payWithStripe
Now, you can make an API call to this URL using POSTMAN or any other API calling application, or simply a curl request from the terminal. Remember, you need to send the amount, currency, and token information in this POST API call as well.
Deploy Firebase Function to live site
Once your local testing is successful, deploy the firebase functions to the live server using
$ firebase deploy --only functions
This will deploy the functions on your live Firebase server, which you can make API calls to. The URL of the function will again be shown in the terminal after deployment, something like
https://us-central1-shoppr-c97a7.cloudfunctions.net/payWithStripe
Node Express Server
So In this part, we will make the REST API for handling the Stripe charge request.
So first of all you have to run the npm init command which will generate the package.json file in your root project folder which will keep track of all your dependencies in the node project.
After that, you can just create index.js file manually in the root project folder and then the project folder structure will look like this
Now to install the required libraries we can run the following commands
$ npm i express $ npm i cors $ npm i stripe
express — It is a node framework that makes our work easier for the creation of REST APIs.
cors — It is a library that helps us to enable CORS with various options.
stripe — It will help us to use the stripe APIs in our node project
After combining all of the code our index.js will look like this
We have implemented the same function as we have done in firebase functions. Now we start our server locally using the following command
$ node index
Our server will start on localhost: 3000
Step 4 — Connect app/PWA to live Firebase server or Node Server and complete payment requests
To enable our app to make HTTP requests, we import HttpClient
in our app.module.ts
and in our stripe.page.ts
page
import { HttpClient } from "@angular/common/http";
...
constructor(private http: HttpClient){}
Once, we receive the token in response from Stripe server (Step 1 / Step 2), we will call the REST API connecting the app to our Firebase server or Node Server
firebaseURL = 'https://us-central1-shoppr-c97a7.cloudfunctions.net/payWithStripe';
nodeURL = 'http://localhost:3000';
makePayment(token) { this.http .post(this.firebaseURL, { amount: 100, currency: "usd", token: token.id }) .subscribe(data => { console.log(data); }); }
If you are using Node server you can replace this.firebaseURL with this.nodeURL
A successful response from the server will look like the following. It’s a long response, but you get the idea that everything you need is in there, right?
Conclusion
I know it is a long post with a lot to understand. Let me repeat the gist of the post —
Stripe payment consists of two parts — front-end (tokenization) and back-end (actual payment request). The Stripe payment integration will follow this pictorial flow
The front-end part can be done using
- Ionic Native Plugin — Apps / PWA
- Stripe.js (Stripe Elements) — Apps / PWA
The back-end part can be done using
- Firebase functions
- Node Express REST API
Stay tuned for more Ionic 5 blogs !