Apple Wallet pass setup.
Turn on the iOS Apple Wallet pass for Frontelio Access. The phone becomes the credential — Add to Apple Wallet, double-click home, tap reader. Cert provisioning is one-time and takes about 30 minutes.
What the pass is
Apple doesn't let third-party apps emulate NFC cards (Android does — that's the HCE service Frontelio uses on Android). On iOS we use the supported alternative: a PassKit Passcontaining a QR code. The worker adds the pass to Apple Wallet once, double-clicks home / Side Button, holds the phone up to a reader, the reader's camera (or the bridge's PN532 + QR cam) reads the QR, the door opens.
The QR code on the pass IS the daily-rotating credential JWT — the same one Android broadcasts via HCE. When the credential rotates at 00:00 Asia/Dubai (or any time we manually push), we send a silent APNs push to every registered device; iOS quietly refetches the pass with the new QR.
Prerequisites
- Apple Developer Program membership for Frontelio (Team ID
55MVF9UKG9). - Access to
developer.apple.comwith sign-in rights to create Pass Type IDs and certificates. - A Mac with Keychain Access for the CSR + .p12 export step.
- SSH access to the production API droplet to set env vars.
Provisioning walkthrough
Step 1 — Create a Pass Type ID
- Go to developer.apple.com · Identifiers · Pass Type IDs.
- Click the + button.
- Description:
Frontelio Access. - Identifier:
pass.com.missan.frontline.access. - Save.
Step 2 — Generate a CSR in Keychain Access
- On the Mac, open Keychain Access.
- Menu → Certificate Assistant → Request a Certificate From a Certificate Authority…
- User Email:
support@frontelio.com. Common Name:Frontelio Access — Pass Type. CA Email: leave blank. - Select Saved to disk. Save the
.certSigningRequestfile somewhere safe.
Step 3 — Sign the Pass Type certificate
- Back on developer.apple.com, click the Pass Type ID you just created.
- Click Create Certificate.
- Upload the
.certSigningRequestfrom step 2. - Download the resulting
pass.cerfile when prompted.
Step 4 — Export the cert as a password-protected .p12
- Double-click the downloaded
pass.cer— Keychain Access installs the cert + private key together under your login keychain. - In Keychain Access, find the cert (search
pass.com.missan.frontline.access). Right-click → Export… - File format:
Personal Information Exchange (.p12). Save asfrontelio-pass.p12. - Set a strong password — keep this safe in 1Password as
PASS_CERT_PASSWORD.
Step 5 — Download the Apple WWDR intermediate (G4)
The .pkpass signature chain needs Apple's WWDR Certificate Authority. Apple publishes the latest revision (G4) directly:
curl -O https://www.apple.com/certificateauthority/AppleWWDRCAG4.cerConvert from DER to PEM with openssl:
openssl x509 -inform DER -in AppleWWDRCAG4.cer -out AppleWWDRCAG4.pemStep 6 — Base64-encode both files
# .p12 (binary) → single-line base64
base64 -i frontelio-pass.p12 -o pass-cert.b64.txt
# WWDR PEM (text already) → base64 to keep the env var clean
base64 -i AppleWWDRCAG4.pem -o wwdr.b64.txtStep 7 — Generate a wallet auth secret
The pass embeds an authenticationTokenApple uses on every web-service call back to us. It's an HMAC keyed by a per-tenant secret you generate once:
openssl rand -hex 32Save the output as WALLET_PASS_AUTH_SECRET in 1Password.
Step 8 — Set env vars on the production droplet
SSH into the API droplet, edit /etc/frontelio/api.env (or wherever your env file lives) and add:
PASS_TYPE_ID=pass.com.missan.frontline.access
PASS_CERT_P12_BASE64=<paste contents of pass-cert.b64.txt>
PASS_CERT_PASSWORD=<the password you set in step 4>
WWDR_CERT_PEM_BASE64=<paste contents of wwdr.b64.txt>
APPLE_TEAM_ID=55MVF9UKG9
WALLET_PASS_AUTH_SECRET=<the openssl rand -hex 32 from step 7>
# Optional — defaults are fine for production:
# WALLET_PASS_WEB_SERVICE_URL=https://api.frontelio.com/api/v1/access/wallet/v1/
# APNS_GATEWAY_HOST=gateway.push.apple.comThen restart the API container:
docker compose restart apiStep 9 — Test from the staff app
- Open the Frontelio staff app on an iPhone signed in as any worker with at least one active Access grant.
- Tap More → My Access.
- Tap the black Add to Apple Wallet button below the QR card.
- iOS opens the Wallet "Add" sheet. Tap Add in the top-right.
- Done — the pass lives in Apple Wallet. Double-click the Side Button to surface it; the QR is the daily credential.
Rotating the cert (every year)
Apple Pass Type certs are valid for 1 year. Track the renewal date when you set it up, and roughly two weeks before expiry:
- Repeat steps 2–6 with a fresh CSR.
- Set the new
PASS_CERT_P12_BASE64+PASS_CERT_PASSWORDin env. - Restart the API container — the next pass issued uses the new cert. Existing devices auto-refresh on the next push.
Troubleshooting
- "Apple Wallet pass generation is not configured" (503 from
/access/wallet/pass.pkpass) — at least one of the env vars is missing. The error message lists each missing key by name. - iOS Wallet rejects the pass — usually a stale WWDR. Apple has rotated through G1 → G2 → G3 → G4; using the wrong version makes every modern iPhone refuse to add the pass. Re-download from the link in step 5.
- Pass adds but daily refresh doesn't arrive — check the API logs for
APNs returned HTTPwarnings. Most common cause: the Pass Type cert and the APNs identity cert have to be the SAME .p12 — we re-use it for both. If you used a separate cert for APNs you'll see TLS handshake failures. - Verify what the pass looks like — rename the downloaded
.pkpassto.zipand unzip;pass.jsonis human-readable and tells you whether the QR data, fields, and webServiceURL look right.