Build1 publisher3 min readPublished
A Pass Designer walkthrough still signs per-user Wallet passes on a Mac
Apple's Pass Designer builds and signs .pkpass bundles in the browser, says a dev.to guide that still signs its own loyalty cards on an EC2 Mac. Per-user passes are new payloads, so the private key stays on a macOS host the team runs.
The Engineer · Build desk
Drafted by a language model from the sources cited here and checked against its claim ledger before publication. How we use AISend a correction

What happened
- Its JSON export leaves placeholders such as {{SERIAL}}, {{CODE}} and {{BALANCE}} for the serial number, barcode message and balance.
- The guide fills those placeholders with Jinja2 inside a Flask service on every request to issue a loyalty card.
- The author runs the signer on a separate Mac host to keep the secret off the main Linux fleet and to satisfy compliance.
Compiled by The EngineerSomething wrong?How this is made
Why it matters
- contradiction The guide's promise of passes without a Mac holds for a pass shipped unchanged; its own per-user design still puts a Mac in the signing path.
- decision Teams issuing per-user passes still have to choose where the account's private key lives and operate a signing host next to it.
- cost For dynamic passes, an EC2 Mac instance or other macOS host remains a running cost alongside the Linux fleet.
- capability Designers can build and validate a layout in a browser, so schema and image-size errors surface before a payload reaches the signer.
The export is a template. The JSON the portal hands back has `{{SERIAL}}`, `{{CODE}}` and `{{BALANCE}}` where the serial number, barcode message and balance go [6]. The guide renders that file through Jinja2 inside a Flask service on every request, injecting the user ID, QR code and balance [7]. Every pass a customer downloads is a payload the portal never saw, so the signature the portal produced does not cover it [1].
The post says plainly where signing ends up. It keeps signing off the portal because "the actual signing requires the private key from your Apple developer account" [8]. The Flask service posts the rendered JSON to an internal signing endpoint. Behind that endpoint is a macOS-based Docker container on an EC2 Mac instance. It mounts the certificate, signs the payload with signpass, Apple's command-line tool, and streams the .pkpass back for each issued pass [9].
The split is sound engineering on its own terms. The author says it keeps the secret off the main Linux fleet and satisfies compliance [10]. I'd keep that split even if the portal grew a signing API. One host holding the certificate is easier to audit than a key copied to every node.
The post's line that passes can now be built "without needing Xcode or a Mac app" holds for one case [1]. A pass designed once and handed out unchanged comes out of the portal as a full bundle of JSON, assets and signature, ready to serve from a backend or a mobile-first website, according to the post [2]. A loyalty card with a live balance is a different case, and the guide's own architecture for it still runs on a Mac [9].
What the portal does remove is the layout loop. It checks field lengths, image dimensions and required fields against Apple's schema [3]. The guide uploads a 300 by 300 pixel PNG logo and a 640 by 960 background, and says the UI warns if the dimensions are off [5]. Before this, the author had to "spin up a macOS VM" and "manually zip assets", and credits the UI with "shaving hours off the feedback loop" [11]. That saving transfers if your iteration cost was a VM boot per layout change. I'd expect teams whose layout is settled, and whose failures come from the data feed, to save much less.
The CI claim is narrower than it sounds. The post says the exported JSON can be fed straight into CI pipelines [4]. What CI receives is the template file. The signing step is still an HTTP call to the Mac [9]. The listing also needs work before it runs: it imports json, base64 and subprocess, then calls `requests.post` and `io.BytesIO` [12]. The first request to `/issue` would fail with a NameError [2].
All of this comes from one walkthrough on dev.to. The post says the portal's .pkpass is the same artifact a fully scripted build would produce [13]. It does not say whose certificate the portal signs with [14].
What to watch
- Apple documentation stating whose Pass Type ID certificate the portal signs with, and whether it is the team's own.
- A portal API or CLI that signs rendered payloads, which would take the Mac host out of the per-user pass path.
- Whether the Template ID the portal returns can be referenced from a build pipeline or is only a handle inside the UI.