Apple recently added a new authentication method to APNS ( Apple Push Notification Authentication Key (Sandbox & Production)).
The downloaded key is a .p8
file with a private key:
$ cat APNSAuthKey_3HHEB343FX.p8
-----BEGIN PRIVATE KEY-----
MIGTAgEAMBMGByqGSM49AgEGCCqGSM49AwEHBH...Already.Revoked...lHEjCX1v51W
-----END PRIVATE KEY-----
I am using APNs messages using the old method - adding them to keychain, asking for a certificate and using OpenSSL to send messages to gateway.production.push.apple.com:2195
.
How do I send push notifications using standard CLI Linux tools (OpenSSL, Python etc.) using the new format?
If you have curl with HTTP/2 support and openssl with ECDSA support installed on your machine, you can use the following script to test push notifications using an APNs Auth Key:
#!/bin/bash
deviceToken=b27371497b85611baf9052b4ccfb9641ab7fea1d01c91732149c99cc3ed9342f
authKey="./APNSAuthKey_ABC1234DEF.p8"
authKeyId=ABC1234DEF
teamId=TEAM123456
bundleId=com.example.myapp
endpoint=https://api.development.push.apple.com
read -r -d '' payload <<-'EOF'
{
"aps": {
"badge": 2,
"category": "mycategory",
"alert": {
"title": "my title",
"subtitle": "my subtitle",
"body": "my body text message"
}
},
"custom": {
"mykey": "myvalue"
}
}
EOF
# --------------------------------------------------------------------------
base64() {
openssl base64 -e -A | tr -- '+/' '-_' | tr -d =
}
sign() {
printf "$1" | openssl dgst -binary -sha256 -sign "$authKey" | base64
}
time=$(date +%s)
header=$(printf '{ "alg": "ES256", "kid": "%s" }' "$authKeyId" | base64)
claims=$(printf '{ "iss": "%s", "iat": %d }' "$teamId" "$time" | base64)
jwt="$header.$claims.$(sign $header.$claims)"
curl --verbose \
--header "content-type: application/json" \
--header "authorization: bearer $jwt" \
--header "apns-topic: $bundleId" \
--data "$payload" \
$endpoint/3/device/$deviceToken
NOTE: I use a slight variation of this script for testing on macOS with homebrew versions of curl and openssl: http://thrysoee.dk/apns/
@JessThrysoee Your "slight variation" works like a CHAMP. Thanks for posting your hard work for all to see, it's people like you that keep the community juiced +1
Thank you for this very helpful script. On my Mac, I had to add the "--with-nghttp2" option to install curl with http2 support (as the home-brew curl doesn't currently seem to have the http2 support by default): brew install curl --with-nghttp2. (or as I already had curl installed: brew reinstall curl --with-nghttp2 ) Then on the curl command in the script, I added the option: --http2 and script works well. Thank you.
I keep getting "unable to load key file"
As a note, curl must be compiled with OpenSSL and nghttp2 if using brew:
brew install --with-openssl --with-nghttp2 curl
@Neil I have updated the macOS script with your homebrew curl-openssl change. Thanks.