Skip to main content

Creating Apple Wallet Passes

Creating Apple Wallet Passes must occur on a backend server as mobile apps are restricted from generating them.

This tutorial will walk you through a sample backend service that generates Apple Wallet Passes developed in NodeJS using a Cloudflare Worker. The principles applied in this tutorial apply to other server stacks and their programming languages.

A Sample Project is available if you would prefer to look at code.

There are 3 main steps in creating a pass:

  1. Designing - Similar to HTML, a pass needs to be designed to show the information you want on it.
  2. Signing - A pass file needs to signed to prove that it was issued by your app.
  3. Delivering - Sending the pass to your app via an API.

Designing​

Apple documents the manual content and design of a pass but there are 3rd party designers like Passkit Visual Designer to help.

You can use the sample project as a design template: The model folder contains the necessary images and pass.json file that defines the structure of the pass:


_31
{
_31
"formatVersion": 1,
_31
"passTypeIdentifier": "pass.io.ionic.example",
_31
"serialNumber": "nmyuxofgna",
_31
"teamIdentifier": "F53WB8AE67",
_31
"webServiceURL": "https://192.168.1.254:80/",
_31
"authenticationToken": "vxwxd7J8AlNNFPS8k0a0FfUFtq0ewzFdc",
_31
"relevantDate": "2022-12-08T13:00-08:00",
_31
"locations": [
_31
{
_31
"longitude": -122.3748889,
_31
"latitude": 37.6189722
_31
},
_31
{
_31
"longitude": -122.03118,
_31
"latitude": 37.33182
_31
}
_31
],
_31
"barcodes": [
_31
{
_31
"message": "123456789",
_31
"format": "PKBarcodeFormatQR",
_31
"messageEncoding": "iso-8859-1"
_31
}
_31
],
_31
"organizationName": "Apple Inc.",
_31
"description": "A Booking pass",
_31
"foregroundColor": "rgb(255, 255, 255)",
_31
"backgroundColor": "rgb(253, 123, 35)",
_31
"boardingPass": {}
_31
}

Signing a Pass​

A pass is signed digitally using a developer and WWDR certificates. This sample code uses a node library passkit-generator which takes the following inputs:

  • signerCert - This is your signing certificate
  • signerKey - This is your signing key
  • signerKeyPassphrase - This is your signing key passphrase
  • wwdr - This is the WWDR Certificate

To get these properties we need to create a Pass Type identifier, set our team identifier, create a certificate and finally use these properties and files to sign a pass. These steps are outlined below:

1. Create a Pass Type Identifier​

Visit your Apple Developer Account and register a new Pass Type ID with Apple (This is found in Certificates, Identifiers & Profiles > Identifiers > + button).

Take this value and paste it in index.ts in the variable passTypeIdentifier or paste it into the passTypeIdentifier property in models/pass.json.

2. Set Team ID​

In index.ts set the variable teamIdentifier to the team ID found in your Apple Developer Account.

3. Create a Certificate and Key​

First, create a private key via the command line:


_10
openssl genrsa -out my-key.key 2048

We then create a Certificate Signing Request (CSR) using the private key:


_10
openssl req -new -key my-key.key -out request.certSigningRequest

Important: You must specify a challenge password (used for SIGNER_PASSPHRASE later).

In the Apple Developer Portal select the Pass Type Identifier you created earlier and click the Create Certificate button.

Provide a certificate name and select Choose File to upload your CSR. Click the Download button and save the pass.cer file.

We need to convert this cer file to pem format:


_10
openssl x509 -inform DER -outform PEM -in pass.cer -out pass.pem

4. Download the WWDR Certificate​

You'll need the WWDR (Apple WorldWide Developer Relations) G4 Certificate which can be downloaded here.

You'll need to convert this cer to pem format as well:


_10
openssl x509 -inform DER -outform PEM -in AppleWWDRCAG4.cer -out wwdr.pem

The 3 important secret files: wwdr.pem, pass.pem, my-key.key are text based and passed into our node application in index.ts. From here the implementation is specific to CloudFlare Workers.

CloudFlare Worker Setup​

CloudFlare Workers are node apps that run on CloudFlare. A CLI tool called Wrangler should be installed to deploy your worker.

In wrangler.toml set the name to a unique name for your worker. Run npx wrangler deploy which will login to CloudFlare and deploy the CloudFlare worker. After deploying you can login to CloudFlare, click Workers & Pages and see your worker under Overview.

You should go the CloudFlare workers Settings > Variables and create the variables for SIGNER_CERT, SIGNER_KEY, SIGNER_PASSPHRASE and WWDR with the values from the text files and password you created in previous steps.

Test the Pass​

When you visit the url for your Cloudflare Worker (eg in a web browser) it should attempt to download a pkpass file. If it does not, look in Logs > Real-time Logs and see what error has been reported. The usual problems will be:

  • SIGNER_CERT variable was not set to the text content of the pass.pem file you created
  • SIGNER_KEY variable was not set to the text content of the my-key.key file you created
  • SIGNER_PASSPHRASE variable does not match the challenge password you entered when creating the certificate signing request
  • WWDR variable was not set to the text content of the wwdr.pem file or the certificate was generated from something other than the G4 certificate
  • A certificate has expired

You can now test your cloudflare worker url for a pass in the front end application. Common failures found in the front end include:

  • Your teamIdentifier not matching your Team Identifier in your Apple Developer Account
  • Your application needing CORs access to download the pkpass

If the pass correctly generates and downloads you should see a screen like below after a second or two:

App Screenshot

Other Documentation​

See the passkit generator repo for similar examples and additional information.

Apple Documentation​

Apple provides a good introduction to creating your first pass, designing passes and distributing passes.

While you can manually create passes it is best to have a backend server create the pass and provide it to the app. This is because passes are digitally signed using a Pass Type ID and Production Certificate created in your Apple Developer Account.

Changing Passes​

A pass can change over time. For example: an airline pass can be changed if a plane is delayed, a ID Card can change after it has expired or a ticket can change when it has been transferred to another person.

Apple provides a way to change a pass through push notifications. See Working with Passes.