Connect to APNS via HTTP/2 with PHP
Tags: ios, php, webdev, opensource
Published: 2020-01-04 20:22:23

# Send a push message via APNs with a PHP Script

HTTP/2 is the new standard (and from November 2020 onwards the only way to connect to the APNS) in this article i’ll explain how to use PHP to connect to APNS using JWT token (recommended) or by using certificates.

Apple’s service to send push notifications to iPhones, iPads and even to Apple’s watches is called APNS: Apple Push Notification Service) .

In order to send Push Notifications you’ll need an IOS app and a server to send the message from. In this article I will provide information on how to send the messages via PHP using a library to make it easier to generate the required JWT token.

## What do you need in order to send Push Notifications via APNS?

The delivery of remote notifications involves several key components. We’ll be needing a receiver (iPad, iPhone, ect) and a server to send the message from (provider server)

- Your company’s/personal server (known as the provider server)
-- we’ll be using PHP on our provider server
- Apple Push Notification service (APNs)
-- Private key (or certificate) from Apple (.p8 file)
- The user’s (apple) device (iPad, iPhone, ect.)
- IOS application (Your app running on the user’s device)
-- for example: nl.samauto.ios-application

### Getting the private key from Apple

Apple Push Notification service (APNs) must know the address of a user’s device before it can send notifications to that device. The address takes the form of a device token unique to both the device and your app ( nl.samauto.ios-application ) . At launch time, your app communicates with APNs and receives its device token, which you then forward to your provider server (the one we are going to build with PHP). Our server will include that token with any notifications it sends to Apple.

Head over to [Developer.apple.com](https://developer.apple.com) and login with your AppleId.

*Go to “Certificates, Identifiers & Profiles > Keys“*

Generate a new key for your application, make sure to enable the Push Notifications Capability.

Download the .p8 file and save it to a secure location.

**IT CANNOT BE DOWNLOADED AGAIN** (APPLE DELETES THE PRIVATE KEY)

### Let's build the PHP Server!

We’ll be building our server with PHP.

To authenticate to APNS we are utilizing JWT (JSON Web Tokens – RFC 7519) to create a Token Based Authenticated connection to Apple’s servers.

We will use composer to add a package (jwt) developed by Luís Cobucci. [lcobucci/jwt on GitHub](https://github.com/lcobucci/jwt) or [at packagist.org](https://packagist.org/packages/lcobucci/jwt)

To add the package (via composer) to the project use the following command:

```
composer require lcobucci/jwt
```

We can use the following script:

```php
<?php

use Lcobucci\JWT\Signer\Key;
use Lcobucci\JWT\Signer\Ecdsa\Sha256;
use Lcobucci\JWT\Configuration;

$config = $container->get(Configuration::class);
assert($config instanceof Configuration);

$device_token = "device_token_here";
$apns_topic = 'to.dev.ios-application';
$p8file = "/home/dave/samauto/key_from_apple.p8";

$token = (string) $config->createBuilder()
->issuedBy("DEF123GHIJ") // (iss claim) // teamId
->issuedAt(time()) // time the token was issuedAt
->withHeader('kid', "ABC123DEFG")
->setKey('file://' . $p8file)
->setSigner(new Sha256()) // APNs only supports the ES256 algorithm
->getToken(); // get the generated token

$payloadArray['aps'] = [
  'alert' => [
    'title' => "Dev.To Push Notification", // title of the notification
    'body' => "Visit SamAuto.nl for more awesome scripts", // content/body of the notification
  ],
  'sound' => 'default',
  'badge' => 1
];

$payloadJSON = json_encode($payloadArray);

$url = "https://api.sandbox.push.apple.com/3/device/$device_token";
$ch = curl_init($url);

curl_setopt($ch, CURLOPT_POSTFIELDS, $payloadJSON);
curl_setopt($ch, CURLOPT_HTTP_VERSION, CURL_HTTP_VERSION_2);
curl_setopt($ch, CURLOPT_HTTPHEADER, ["Authorization: Bearer $token","apns-topic: $apns_topic"]);
$response = curl_exec($ch);
$httpcode = curl_getinfo($ch, CURLINFO_HTTP_CODE);

// On successful response you should get true in the response and a status code of 200
// A list of responses and status codes is available at
// https://developer.apple.com/library/ios/documentation/NetworkingInternet/Conceptual/RemoteNotificationsPG/Chapters/TheNotificationPayload.html#//apple_ref/doc/uid/TP40008194-CH107-SW1

var_dump($response);
var_dump($httpcode);
```

I will explain the script in steps.
First we'll need a deviceId from a IOS device, the application identifier of your application installed on the IOS device and the filePath to the .p8 file.

```
// replace the device token with "device_token_here"
$device_token = "device_token_here";

// use your IOS application ID
$apns_topic = 'to.dev.ios-application';

// replace $p8file with the location to your .p8 file you downloaded from Apple.
$p8file = "/home/dave/samauto/key_from_apple.p8";
```


Next we will use the JWT library to generate a JWT token to authenticate the HTTP/2 call to Apple's API.

```
// Replace "DEF123GHIJ" with your TeamId
// Replace "ABC123DEFG" with your (Encryption) KeyId

$token = (string) $config->createBuilder()
->issuedBy("DEF123GHIJ") // (iss claim) // teamId
->issuedAt(time()) // time the token was issuedAt
->withHeader('kid', "ABC123DEFG")
->setKey('file://' . $p8file)
->setSigner(new Sha256()) // APNs only supports the ES256 algorithm
->getToken(); // get the generated token

// $token will now contain a JWT Token for example:
// eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiIxMjM0NTY3ODkwIiwibmFtZSI6IkpvaG4gRG9lIiwiaWF0IjoxNTE2MjM5MDIyfQ.SflKxwRJSMeKKF2QT4fwpMeJf36POk6yJV_adQssw5c

```

You can find out more about JWT tokens on [JWT.IO](https://jwt.io)

The next part of the script is creating a payload to send to apple and encode is as JSON.

```
$payloadArray['aps'] = [
  'alert' => [
    'title' => "Dev.To Push Notification", // title of the notification
    'body' => "Visit SamAuto.nl for more awesome scripts", // content/body of the notification
  ],
  'sound' => 'default',
  'badge' => 1
];

$payloadJSON = json_encode($payloadArray);

```

The payload will look like this:
```
{
	"aps": {
		"alert": {
			"title": "Dev.To Push Notification",
			"body": "Visit SamAuto.nl for more awesome scripts"
		},
		"sound": "default",
		"badge": 1
	}
}
```

We will send that to Apple's Sandbox URL (https://api.sandbox.push.apple.com/)
And append "3/device/" and the value of $device_token
Next we will build a cURL request (make sure you have a HTTP/2 enabled version of CURL installed)

```
curl_setopt($ch, CURLOPT_POSTFIELDS, $payloadJSON);
curl_setopt($ch, CURLOPT_HTTP_VERSION, CURL_HTTP_VERSION_2);
curl_setopt($ch, CURLOPT_HTTPHEADER, ["Authorization: Bearer $token","apns-topic: $apns_topic"]);
$response = curl_exec($ch);
$httpcode = curl_getinfo($ch, CURLINFO_HTTP_CODE);
```

If all went well you should see a 200 OK HTTP status code.

Happy Hacking!