Simplifying Apple Wallet Pass Generation with Elixir

Faced with tight deadlines and the complexities of Apple's iOS 18 specifications, I developed ex_pass, an Elixir library that simplifies Apple Wallet pass generation. Discover how ex_pass overcomes existing tools' limitations, streamlining PK pass creation for the Elixir community.
Stephen Njau
Stephen Njau
Simplifying Apple Wallet Pass Generation with Elixir

A Journey to streamline wallet passes (.pkpass) generation


Introduction
In mid-August 2024, my team at Mindvalley faced a challenge familiar to many developers working with Apple Wallet passes: generating and managing event passes efficiently under a tight deadline. With Apple’s iOS 18 release on the horizon — and the added pressure of being featured in it — we had just over a week to implement a solution that met Apple’s technical specifications and provided a seamless user experience for our events.

We dove headfirst into a world where Apple Wallet passes required precise handling, cryptographic signing, and ongoing updates, especially with the new specifications in iOS 18. After discovering the limitations of existing libraries in the Elixir ecosystem, I realized we needed a new, more robust solution.

What began as a rush to deliver on time has evolved into a long-term vision: creating an Elixir library that simplifies the entire process of PK pass generation — from signing to distribution and ultimately to updates and registration.

slight tangent
Things got really exciting after all the sweat, collaboration, and late nights, our team’s designs for the event passes were featured during Apple’s iOS 18 reveal. Seeing our work showcased by Apple was a huge moment of pride. It was a testament to the hard work and dedication of everyone on the team, showing that even under tight deadlines, we created something Apple saw as worthy of featuring.

Check out iOS 18 on Apple’s website

https://www.apple.com/sg/ios/ios-18/

Bridging to the Challenge Ahead

But let’s rewind a bit. How did we get to that proud moment on the iOS 18 stage? The journey wasn’t all smooth sailing. In fact, the road was paved with obstacles that tested our problem-solving skills and pushed us to innovate. To understand the significance of our solution, it’s important to dive into the origins of the problem we faced.

Origins of the Problem

Apple Wallet is a powerful tool for managing event passes, coupons, tickets, etc. However, it comes with its own challenges, especially when dealing with tight deadlines and new iOS specifications. When we set out to digitize our event passes at Mindvalley, we quickly realized that while Apple’s documentation was thorough, generating and signing PK passes involved navigating several technical nuances.

Our first challenge was finding tools in the Elixir ecosystem to help with this. Since our backend systems at Mindvalley are primarily built in Elixir, it made sense to develop a solution in the same language for better integration — despite the existence of solutions in other languages like JavaScript and Go. We found Passbook for Elixir, a library by Bounce, but it was clear that it needed maintenance and lacked critical features like runtime validation. This was a key limitation, especially given our project’s time-sensitive nature.

Another significant obstacle was the intricate process of digitally signing the passes, which requires using OpenSSL — an open-source toolkit for SSL and TLS protocols. Apple demands specific fields in precise formats, and errors—like missing time zones—would cause the pass to fail silently without much guidance on what went wrong. Debugging became a painful process. I had to open the debugger on my Mac, sift through logs, and manually identify the issues—not exactly anyone’s idea of a fun afternoon.

I realized that PK pass generation, signing, and validation nuances could be handled more seamlessly without requiring developers to endure the same debugging headaches. These hurdles laid the groundwork for developing a new Elixir library, which I’ll detail in the following sections.

Vision for the Library

With these challenges fresh in my mind, I set out to build a more comprehensive solution for Apple Wallet PK pass generation in Elixir. My goal is to simplify the process for developers while addressing the shortcomings of existing tools.

This vision revolves around a phased approach, with each step designed to address a specific part of the pass lifecycle.

Phase 1: Generation and Signing of Passes.

The first phase focuses on generating and signing Apple Wallet passes with minimal friction.

Enter ex_pass—the Elixir library I'm building. It includes runtime validation, so you don't have to guess what Apple's being picky about; the library will do the nagging for you. If a required field is missing or improperly formatted, ex_pass it returns clear and meaningful error messages. This way, developers don't have to rely on iOS tools or logs to address these issues. By catching problems early, we eliminate the need for tedious debugging through device logs, saving considerable time and effort. No more guesswork on what Apple’s picky about 😁; the library will do the nagging for you.

Phase 2: Updates and Registration

Once the initial generation phase is fully implemented, the next step is handling ongoing wallet pass management. This includes registering the passes on the server, handling updates (like event changes or cancellations), and pushing updates to users via the Apple Push Notification Service (APNs). I aim to simplify this process using a second module or sister library. This additional library will integrate seamlessly with the primary pass-generation library, giving developers a full suite of tools for managing passes in Elixir — even after they’ve been installed on a user’s device.

One of my key goals is to make the library as developer-friendly as possible. This implies providing thorough documentation with examples and detailed guides to help developers get up and running quickly. I also incorporate testing as a first-class citizen, ensuring the library is well-tested across multiple Elixir versions and providing clear exceptions and error messages when something goes wrong.

By breaking the project into these phases, I can address the immediate need for pass generation and signing while also laying the groundwork for future updates and registration, essentially providing developers with a complete solution for handling PK passes.

As a bonus, while we initially built it for iOS, we discovered that the .pkpass format also works on Android. This unexpected win opened up the library to even more flexibility for developers working across platforms. Who doesn’t love a two-for-one deal? 😁

Motivation

When I first set out to solve the problem of generating and managing Apple Wallet passes, it was driven by necessity — our team at Mindvalley needed a quick solution under a tight deadline. However, digging deeper, I realized this was about more than just meeting a deadline. There was a gap in the Elixir ecosystem for tools that handle this type of complex integration smoothly, and I wanted to fill it.

One of my primary motivations for building this library was to make life easier for other Elixir developers. I know firsthand how frustrating it can be to work with systems that don’t provide clear feedback. I wanted to create a tool that removes some of that pain. By offering runtime validation, clear documentation, and solid testing, I aim to reduce developers' time debugging and allow them to focus on delivering great features.

Another driving factor is my commitment to contribute to the Elixir community. I’ve benefited greatly from the work of others who’ve built libraries and tools that make my job easier, and this is my way of paying it forward. I want this library to be something any Elixir developer can pick up and use with confidence, knowing it’s well-maintained and designed with their needs in mind.

Ultimately, my motivation comes from the desire to create something valuable that simplifies a complex process and enables developers to build great products without being bogged down by the technical nuances of wallet pass generation and management.

Call to Action

As I continue to build and refine this library, I’m excited to share my progress with the Elixir community. I’ve already started working on the library, and you can check out the project ex_pass on GitHub.

GitHub - njausteve/ex_pass: ExPass is a robust Elixir library designed to simplify the creation of digital passes compatible with mobile wallets
ExPass is a robust Elixir library designed to simplify the creation of digital passes compatible with mobile wallets - njausteve/ex_pass

A list of open issues is available, so if you’re interested in contributing — whether to help with code, offer feedback, or just explore what’s been built so far — this is a great place to start.

Whether you want to learn something new or contribute to open source, I’d love to have you join the project. I'd also love to hear your thoughts for those working in Elixir who’ve encountered similar challenges with Apple Wallet passes. Your input is invaluable, whether it’s about the pain points you’ve experienced or features you’d like to see in the final product. Together, we can build something simplifying pass generation and management for the entire Elixir community.

Stay tuned for updates — I look forward to sharing more as the library evolves. And remember, life’s too short to spend it sifting through device logs!