Apple recently added a new authentication method to APNS ( Apple Push Notification Authentication Key (Sandbox & Production)).
The downloaded key is a
You can send push notification by NODE JS using Apple Push Notification Authentication Key (Sandbox & Production). There is a tutorial provided by Elad Nava in this link
This tutorial has all steps of creating the Apple Push Notification Authentication Key and setting up a local server to run Node JS code for sending push notification. You can run the code in your local machine and test the push notification.
Hope this will help.
The answer provided by Nicolas Manzini, while helpful, did not fully work for me. I also wanted to use command line curl. In particular, reading in the .p8 file was causing some problems. A modified version:
<?php
$teamid = 'YOURTEAMID';
$keyid = 'A464FN6T93'; // in the name of the file downloaded from Apple Certs
// since it is a universal key, I wanted this in a location accessible to several accounts
$keyFile = '/path/to/file/AuthKey_A464FN6T93.p8';
$privateKey = openssl_pkey_get_private('file://' . $keyFile);
if (! $privateKey) {
die('could not find: ' . $keyFile);
}
$header = ['alg' => 'ES256', 'kid' => $keyid];
$header = base64_encode(json_encode($header));
$claim = ['iss' => $teamid, 'iat' => time()];
$claim = base64_encode(json_encode($claim));
$tok = $header . '.' . $claim;
// pass in empty $signature, 2nd line below fills it
$signature = '';
$result = openssl_sign($tok, $signature, $privateKey, OPENSSL_ALGO_SHA256); // 'sha256'
if (! $result) {
die('unable to create signature');
}
$sign = base64_encode($signature);
openssl_free_key($privateKey);
$jwt = $tok . '.' . $sign;
foreach($tokens as $token) {
$cmd = '\
/usr/local/bin/curl -v \
-d \'{"aps":{"alert":{"title":"Notification Title","body":"You are being notified!"},"sound":"default"}}\' \
-H "apns-topic: com.app.bundle.id" \
-H "authorization: bearer ' . $jwt . '" \
-H "content-type:application/json" \
--http2 \
https://api.push.apple.com/3/device/' . $token . ' 2>&1'; // ending w/ 2>&1, sends output to $output
exec($cmd, $output, $return);
if ($return != 0) {
// be notified of error
}
else {
foreach($output as $line) {
if (strpos($line, 'apns-id')) {
$apns = $line;
}
}
}
}
?>
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/
Voilà in PHP what it looks like with curl and HTTP/2. This script return the 200 ok status code along with the generated token id.
// THE FINAL SCRIPT WITHOUT DEPENDENCIES!!! ...except curl with http2
$device_token = "a0abd886etc...";
//echo $key;
$kid = "YOURKEYID";
$teamId = "YOURTEAMID";
$app_bundle_id = "your.app.bundle";
$base_url = "https://api.development.push.apple.com";
$header = ["alg" => "ES256", "kid" => $kid];
$header = base64_encode(json_encode($header));
$claim = ["iss" => $teamId, "iat" => time()];
$claim = base64_encode(json_encode($claim));
$token = $header.".".$claim;
// key in same folder as the script
$filename = "KeyFromApple.p8";
$pkey = openssl_pkey_get_private("file://{$filename}");
$signature;
openssl_sign($token, $signature, $pkey, 'sha256');
$sign = base64_encode($signature);
$jws = $token.".".$sign;
$message = '{"aps":{"alert":"You are welcome.","sound":"default"}}';
function sendHTTP2Push($curl, $base_url, $app_bundle_id, $message, $device_token, $jws) {
$url = "{$base_url}/3/device/{$device_token}";
// headers
$headers = array(
"apns-topic: {$app_bundle_id}",
'Authorization: bearer ' . $jws
);
// other curl options
curl_setopt_array($curl, array(
CURLOPT_HTTP_VERSION => CURL_HTTP_VERSION_2_0,
CURLOPT_URL => $url,
CURLOPT_PORT => 443,
CURLOPT_HTTPHEADER => $headers,
CURLOPT_POST => TRUE,
CURLOPT_POSTFIELDS => $message,
CURLOPT_RETURNTRANSFER => TRUE,
CURLOPT_TIMEOUT => 30,
CURLOPT_SSL_VERIFYPEER => FALSE,
CURLOPT_HEADER => 1
));
// go...
$result = curl_exec($curl);
if ($result === FALSE) {
throw new Exception("Curl failed: " . curl_error($curl));
}
print_r($result."\n");
// get response
$status = curl_getinfo($curl);
return $status;
}
// open connection
$curl = curl_init();
sendHTTP2Push($curl, $base_url, $app_bundle_id, $message, $device_token, $jws);