How to add Apple Pass on a Flutter project with Firebase

Luca Giordano
5 min readJun 13, 2024

--

In this article I will explain how I have integrated Apple Pass to my Flutter project using Firebase functions.

I am not an expert of backend development and Apple pass design, so maybe some information could be wrong or not so complete. For more detailed information, please refer to the documentation.

Step 1: Preparing the certificates

The first thing to do is preparing the certificates. We have to download three elements:

  • Signer Certificate (Developer)
  • Signer Certificate Key (Developer)
  • WWDR (Apple WorldWide Developer Relations) G4 Certificate
  1. Create a new pass type identifier (direct link) and provide it with a description and a reverse-domain identifier (starting with “pass.”). You will have to put this identifier as a value for passTypeIdentifier in the pass.json file or as a prop.
  2. Open Keychain Access, go to File > Certificate Assistant > Request a Certificate From a Certificate Authority, fill out the form, choose “Save to disk” option and Continue. A new file will be created.
  3. In the list of your passTypeIds (filter), click on your new pass id to edit it.
  4. Click on “Create Certificate”. Enter your Pass certificate Name and upload the file that has just been created with Keychain Access. Then, download the certificate and double click on it (to add it to Keychain Access).
  5. Back to Keychain Access, right click on “Pass Type ID: xxxx” > Export “Pass Type ID: xxxx”. Save it where where you like (with the extension .p12). You now have to create a password. Store it, we will need it later.
  6. Open the Terminal where you saved this .p12 file and enter the commands
# <your-password> for -passin is the pass for the P12
$ openssl pkcs12 -in <cert-name>.p12 -clcerts -nokeys -out signerCert.pem -passin pass:<your-password>

# <your-password> for -passin is the pass for the P12. <secret-passphrase> is the pass you'll pass to passkit-generator to decrypt privateKey.
$ openssl pkcs12 -in <cert-name>.p12 -nocerts -out signerKey.pem -passin pass:<your-password> -passout pass:<secret-passphrase>

If you have some errors, add “-legacy” at the end of the commands, or follow this link.

Store the passphrase, we will need it later.

2 of the 3 certificates we need are generated.

For the last one, just open this link.

Step 2: Preparing the Server side

As we said, we will use Firebase functions to host our pass generator.

Attention: this requires the Blaze Plan (which is not free but “pay-as-you-go”). If you don’t want to use Firebase, simply host the backend we’ll build wherever you like.

To create our pass, we will use passkit-generator.

Let’s start:

flutter login
  • Enter the command
firebase init

select “Functions: Configure a Cloud Functions directory and its files” and choose the project you just created. Then selected “JavaScript” and answer “Y” at every question, except for “Do you want to use ESLint to catch probable bugs and enforce style?” (just to not have Lint exceptions while deploying, you can keep it if you are fine with it).

  • Now open the “functions” folder that should have been created with your code editor.
  • Open the terminal inside the project and install the dependencies
yarn add passkit-generator
yarn add path
yarn add file-system
  • Create a folder “certs” inside the project and paste the 3 certificates we have created
  • Create also a folder “model”, where we will put our pass model.

I will use a simple pass model, with just some labels and a picture. If you are interested in a different model, just follow this link and build your customized json file. Here you can find some samples.

  • Once you have your pass folder ready (eg. “auditor.pass”, which contains the json file and the images), copy it in the “model” folder inside our project.

The project structure should look something like this:

My pass.json file is

Warnings:

  • passTypeIdentifier: has to be the same as the one we registered at the beginning
  • teamIdentifier: has to be your team identifier

Let’s move to “index.js”:

  • Import the dependencies
const functions = require("firebase-functions");
const { PKPass } = require("passkit-generator");
var fs = require("file-system");
var path = require("path");

Use PKPass to create the pass

PKPass.from({
model: "./model/auditor.pass",
certificates: {
wwdr: fs.fs.readFileSync("./certs/wwdr.pem"),
signerCert: fs.fs.readFileSync("./certs/signerCert.pem"),
signerKey: fs.fs.readFileSync("./certs/signerKey.pem"),
signerKeyPassphrase: "YOUR PASSPHRASE"
}

},{})

All together

The flow is pretty simple:

  • When a new request arrives, a pass is generated
  • Then, the information within the request is used to fill out the pass
  • The pass is sent back to the client

NB: the commented line “fs.writeFileSync(“auditor.pkpass”, bufferData)” is useful during the development to store the generated .pkpass file in the folder of our project, so we can easily open it in the emulator to check the result.

Let’s run our backend locally by entering the command

firebase emulators:start    

which should give us back and URL like “http://127.0.0.1:5001/XXXX/us-central1/pass”

When we finish our local development and we want to go on production, use this command to deploy our server.

firebase deploy

Step 3: Flutter app

There are very few things to do on our app.

  • First, import flutter_wallet_card and dio (or an other http client)
  • Use the suggested image to provide the “Add to Apple Wallet” functionality
  • Write the function to handle the onTap action

Then, open the iOS module with XCode and under Runner > Signing & Capabilities click “+ Capability”. Finaly, choose “Allow subset of pass types” and select the pass you have created at the beginning.

And…… that’s it!

Your app is now implementing the “Add to Apple Wallet” functionality.

--

--