Push notifications (APNs)
iOS does not let the iPhone app keep its own connection to wardend in the background. To wake it up when a card appears, wardend sends a push notification through Apple Push Notification service (APNs); the app then fetches the card over the same signed HTTPS channel as always.
Push is optional. Without an apns section in the config everything works as before: the app sees cards by long poll, and ntfy can ping it if you set ntfy_url.
What is in a push
Exactly this, for every card:
{"aps":{"alert":{"title":"Approval request","body":"Open to review"},"category":"WARDEN_APPROVAL","sound":"default","interruption-level":"time-sensitive"},"cardId":"wd-…"}
No command, arguments, host, path or risk score. Apple, the lock screen and anyone next to your phone learn only that a card exists. The app then fetches the card itself over the signed channel, recomputes its digest and shows it. The notification expires with the card (apns-expiration) and a repeated push for the same card replaces the previous one (apns-collapse-id).
Create the APNs key in Apple Developer
You need a paid Apple Developer Program membership: free accounts cannot send push notifications.
- Sign in to developer.apple.com/account, open Certificates, Identifiers & Profiles.
- Identifiers: make sure the app ID exists and has the Push Notifications capability enabled: the iOS app (
com.wardenclaw.app). If you build the app yourself, use your own bundle id here and below. - Keys, then +. Give the key a name (for example
wardend APNs), tick Apple Push Notifications service (APNs). If Apple asks you to configure it, choose the environment Sandbox & Production and the team-scoped key (all topics), then Save, Continue, Register. - Download the file
AuthKey_XXXXXXXXXX.p8. Apple lets you download it only once; keep a copy in your password manager. - Note two values: the Key ID (10 characters, shown on the key page and in the file name) and your Team ID (10 characters, under Membership details).
One key serves all your apps and both environments. If it leaks, revoke it on the same Keys page and create a new one: nobody can approve anything with it, but they could send notifications to your devices.
Put the key on the server
The key is a secret: only wardend may read it. For the hardened install (wardend runs as root, config in /etc/wardend):
chmod 600 AuthKey_ABC123DEFG.p8
scp -p AuthKey_ABC123DEFG.p8 server: # to your home on the server, not the shared /tmp; -p keeps mode 600
ssh server
sudo install -o root -g root -m 600 AuthKey_ABC123DEFG.p8 /etc/wardend/AuthKey_ABC123DEFG.p8
rm AuthKey_ABC123DEFG.p8
For a single-user install use install -m 600 AuthKey_ABC123DEFG.p8 ~/.wardend/ instead. wardend checks the permissions at start: a key readable by the group or by everyone stops it in ticket and deny-list modes, like a writable config.
Config
Add an apns key to the object in your existing config.json (sudoedit /etc/wardend/config.json for the hardened install). Don’t replace the file with this snippet: it holds your paired devices and the mode.
{
"apns": {
"key_file": "/etc/wardend/AuthKey_ABC123DEFG.p8",
"key_id": "ABC123DEFG",
"team_id": "TEAM123456",
"topic_ios": "com.wardenclaw.app"
}
}
| Field | Meaning |
|---|---|
key_file |
Path to the .p8 key, mode 0600. |
key_id |
Key ID from Keys. |
team_id |
Team ID from Membership details. |
topic_ios |
Bundle id of the iOS app. Devices may register tokens only for this topic. |
Check the config and restart wardend: sudo wardend config-check --config /etc/wardend/config.json && sudo systemctl restart wardend (a config wardend can’t read would stop wardend, and the agent with it; what config-check checks). If the key can’t be loaded, wardend starts anyway, writes a warning and runs without APNs; wardend status shows the reason under push.error.
Check pushes
- The app registers its push token by itself once you allow notifications.
wardend push listshows the tokens (truncated), their topic and environment. wardend push testsends a test notification (card idwd-test) to every token and prints Apple’s answer for each one. Add--device <deviceId prefix>to test one device.200means Apple accepted it;400 BadDeviceTokenusually means the token’s environment is wrong (a development build usessandbox); a token answered with410is removed.
Protocol
The wire formats (the signed push/register request, the headers wardend sends to Apple) are in the protocol specification, protocol/README.md, section 8.
What the iPhone app needs in Apple Developer: iPhone app. What the notification shows on the lock screen: Notifications on a locked phone.