<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:dc="http://purl.org/dc/elements/1.1/">
  <channel>
    <title>DEV Community: SaMauto</title>
    <description>The latest articles on DEV Community by SaMauto (@samauto).</description>
    <link>https://dev.to/samauto</link>
    <image>
      <url>https://media2.dev.to/dynamic/image/width=90,height=90,fit=cover,gravity=auto,format=auto/https:%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F308368%2Fe73f5c78-9eb6-4e39-b129-d3ba01241033.png</url>
      <title>DEV Community: SaMauto</title>
      <link>https://dev.to/samauto</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/samauto"/>
    <language>en</language>
    <item>
      <title>Connect to APNS via HTTP/2 with PHP</title>
      <dc:creator>SaMauto</dc:creator>
      <pubDate>Sat, 04 Jan 2020 20:22:23 +0000</pubDate>
      <link>https://dev.to/samauto/connect-to-apns-via-http-2-with-php-57oj</link>
      <guid>https://dev.to/samauto/connect-to-apns-via-http-2-with-php-57oj</guid>
      <description>&lt;h1&gt;
  
  
  Send a push message via APNs with a PHP Script
&lt;/h1&gt;

&lt;p&gt;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.&lt;/p&gt;

&lt;p&gt;Apple’s service to send push notifications to iPhones, iPads and even to Apple’s watches is called APNS: Apple Push Notification Service) .&lt;/p&gt;

&lt;p&gt;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.&lt;/p&gt;

&lt;h2&gt;
  
  
  What do you need in order to send Push Notifications via APNS?
&lt;/h2&gt;

&lt;p&gt;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)&lt;/p&gt;

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

&lt;h3&gt;
  
  
  Getting the private key from Apple
&lt;/h3&gt;

&lt;p&gt;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.&lt;/p&gt;

&lt;p&gt;Head over to &lt;a href="https://developer.apple.com"&gt;Developer.apple.com&lt;/a&gt; and login with your AppleId.&lt;/p&gt;

&lt;p&gt;&lt;em&gt;Go to “Certificates, Identifiers &amp;amp; Profiles &amp;gt; Keys“&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;Generate a new key for your application, make sure to enable the Push Notifications Capability.&lt;/p&gt;

&lt;p&gt;Download the .p8 file and save it to a secure location.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;IT CANNOT BE DOWNLOADED AGAIN&lt;/strong&gt; (APPLE DELETES THE PRIVATE KEY)&lt;/p&gt;

&lt;h3&gt;
  
  
  Let's build the PHP Server!
&lt;/h3&gt;

&lt;p&gt;We’ll be building our server with PHP.&lt;/p&gt;

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

&lt;p&gt;We will use composer to add a package (jwt) developed by Luís Cobucci. &lt;a href="https://github.com/lcobucci/jwt"&gt;lcobucci/jwt on GitHub&lt;/a&gt; or &lt;a href="https://packagist.org/packages/lcobucci/jwt"&gt;at packagist.org&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;To add the package (via composer) to the project use the following command:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight plaintext"&gt;&lt;code&gt;composer require lcobucci/jwt
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;We can use the following script:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight php"&gt;&lt;code&gt;&lt;span class="cp"&gt;&amp;lt;?php&lt;/span&gt;

&lt;span class="kn"&gt;use&lt;/span&gt; &lt;span class="nn"&gt;Lcobucci\JWT\Signer\Key&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="kn"&gt;use&lt;/span&gt; &lt;span class="nn"&gt;Lcobucci\JWT\Signer\Ecdsa\Sha256&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="kn"&gt;use&lt;/span&gt; &lt;span class="nn"&gt;Lcobucci\JWT\Configuration&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="nv"&gt;$config&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nv"&gt;$container&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="na"&gt;get&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;Configuration&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="na"&gt;class&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="nb"&gt;assert&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;$config&lt;/span&gt; &lt;span class="k"&gt;instanceof&lt;/span&gt; &lt;span class="nx"&gt;Configuration&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

&lt;span class="nv"&gt;$device_token&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;"device_token_here"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="nv"&gt;$apns_topic&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s1"&gt;'to.dev.ios-application'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="nv"&gt;$p8file&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;"/home/dave/samauto/key_from_apple.p8"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="nv"&gt;$token&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;string&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="nv"&gt;$config&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="na"&gt;createBuilder&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="na"&gt;issuedBy&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;"DEF123GHIJ"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="c1"&gt;// (iss claim) // teamId&lt;/span&gt;
&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="na"&gt;issuedAt&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nb"&gt;time&lt;/span&gt;&lt;span class="p"&gt;())&lt;/span&gt; &lt;span class="c1"&gt;// time the token was issuedAt&lt;/span&gt;
&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="na"&gt;withHeader&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;'kid'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s2"&gt;"ABC123DEFG"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="na"&gt;setKey&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;'file://'&lt;/span&gt; &lt;span class="o"&gt;.&lt;/span&gt; &lt;span class="nv"&gt;$p8file&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="na"&gt;setSigner&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nx"&gt;Sha256&lt;/span&gt;&lt;span class="p"&gt;())&lt;/span&gt; &lt;span class="c1"&gt;// APNs only supports the ES256 algorithm&lt;/span&gt;
&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="na"&gt;getToken&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt; &lt;span class="c1"&gt;// get the generated token&lt;/span&gt;

&lt;span class="nv"&gt;$payloadArray&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s1"&gt;'aps'&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;
  &lt;span class="s1"&gt;'alert'&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;
    &lt;span class="s1"&gt;'title'&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="s2"&gt;"Dev.To Push Notification"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="c1"&gt;// title of the notification&lt;/span&gt;
    &lt;span class="s1"&gt;'body'&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="s2"&gt;"Visit SamAuto.nl for more awesome scripts"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="c1"&gt;// content/body of the notification&lt;/span&gt;
  &lt;span class="p"&gt;],&lt;/span&gt;
  &lt;span class="s1"&gt;'sound'&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="s1"&gt;'default'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="s1"&gt;'badge'&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;
&lt;span class="p"&gt;];&lt;/span&gt;

&lt;span class="nv"&gt;$payloadJSON&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nb"&gt;json_encode&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;$payloadArray&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

&lt;span class="nv"&gt;$url&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;"https://api.sandbox.push.apple.com/3/device/&lt;/span&gt;&lt;span class="nv"&gt;$device_token&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="nv"&gt;$ch&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nb"&gt;curl_init&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;$url&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

&lt;span class="nb"&gt;curl_setopt&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;$ch&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;CURLOPT_POSTFIELDS&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nv"&gt;$payloadJSON&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="nb"&gt;curl_setopt&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;$ch&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;CURLOPT_HTTP_VERSION&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;CURL_HTTP_VERSION_2&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="nb"&gt;curl_setopt&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;$ch&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;CURLOPT_HTTPHEADER&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s2"&gt;"Authorization: Bearer &lt;/span&gt;&lt;span class="nv"&gt;$token&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="s2"&gt;"apns-topic: &lt;/span&gt;&lt;span class="nv"&gt;$apns_topic&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="p"&gt;]);&lt;/span&gt;
&lt;span class="nv"&gt;$response&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nb"&gt;curl_exec&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;$ch&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="nv"&gt;$httpcode&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nb"&gt;curl_getinfo&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;$ch&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;CURLINFO_HTTP_CODE&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

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

&lt;span class="nb"&gt;var_dump&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;$response&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="nb"&gt;var_dump&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;$httpcode&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;I will explain the script in steps.&lt;br&gt;
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.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight plaintext"&gt;&lt;code&gt;// 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";
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;Next we will use the JWT library to generate a JWT token to authenticate the HTTP/2 call to Apple's API.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight plaintext"&gt;&lt;code&gt;// Replace "DEF123GHIJ" with your TeamId
// Replace "ABC123DEFG" with your (Encryption) KeyId

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

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

&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;You can find out more about JWT tokens on &lt;a href="https://jwt.io"&gt;JWT.IO&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;The next part of the script is creating a payload to send to apple and encode is as JSON.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight plaintext"&gt;&lt;code&gt;$payloadArray['aps'] = [
  'alert' =&amp;gt; [
    'title' =&amp;gt; "Dev.To Push Notification", // title of the notification
    'body' =&amp;gt; "Visit SamAuto.nl for more awesome scripts", // content/body of the notification
  ],
  'sound' =&amp;gt; 'default',
  'badge' =&amp;gt; 1
];

$payloadJSON = json_encode($payloadArray);

&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;The payload will look like this:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight plaintext"&gt;&lt;code&gt;{
    "aps": {
        "alert": {
            "title": "Dev.To Push Notification",
            "body": "Visit SamAuto.nl for more awesome scripts"
        },
        "sound": "default",
        "badge": 1
    }
}
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



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

&lt;div class="highlight"&gt;&lt;pre class="highlight plaintext"&gt;&lt;code&gt;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);
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;If all went well you should see a 200 OK HTTP status code.&lt;/p&gt;

&lt;p&gt;Happy Hacking!&lt;/p&gt;

</description>
      <category>ios</category>
      <category>php</category>
      <category>webdev</category>
      <category>opensource</category>
    </item>
  </channel>
</rss>
