3

I have a seemingly standard task of sending push notifications to Apple devices from a server written in Java. I have never done that in the past, so I went to tutorials and Apple documentation.

1) The APN Provider API claims that THE protocol to send push notifications from the server is HTTP/2. I failed to find any tutorials describing how to do so (I wanted those mostly as a sign that I'm not the first one to do that and maybe for references to the most popular tools/libraries). I found several tutorials (Ray Wenderlich tutorial probably being the most cited) that teach how to send push notifications using the binary protocol. Most GitHub projects use it as well (e.g. a "push notification simulator kit from a Ray Wenderlich tutorial", a popular "pushmeup" ruby gem, a very popular notnoop/java-apns library and so on). Now, the Apple docs have a section for binary provider API which states that

The legacy binary interface required your provider server to employ the binary API described in this appendix. All developers should migrate their remote notification provider servers to the more capable and more efficient HTTP/2-based API described in APNs Provider API.

This definitely sounds like I shouldn't be using the binary API for new development... Even more so since the binary API requires usage (periodic polling) of a separate Feedback service for "dead" device tokens (or else you might be blocked they say), while the new HTTP/2 API gives this information as a response to each individual request, which looks like less moving parts.

As for the HTTP/2, there is a Java library CleverTap/apns-http2 which is even relatively popular, but it uses Jetty HTTP/2 client, and for it to work one needs to start JVM with an ALPN jar on the boot classpath, and that jar corresponds approximately 1-to-1 with JDK versions (which means that if your development uses 1.8.0u92 and your production uses 1.8.0u91 then there should be different jars put). That looks like a very brittle configuration to me in general and hard to apply in my case (each developer has his own VM + common dev VM + test server + prod) -- I don't think it's worth the effort to freeze one version on all of the machines and that these won't diverge with time; all I know is that all of them use JDK 8, but minor versions are out of my control. This need for the ALPN jar will be the case until JDK 9 is out (and adopted widely) which means 1+ year, and it is the case for Jetty and Netty and okhttp3 and I guess any Java library.

2) As if this was not enough, there are also two authentication schemes described by the Apple docs: using a certificate ("old style") vs using JWT. The certificate approach is tried-and-true, but from the docs it looks like the certificate should be regenerated every year while JWTs don't (or to be more precise JWTs are regenerated every hour automatically and so that will be baked into the application and hopefully won't require any manual administrative actions that can be forgotten etc.). The only problem with JWT for me is that

After you create the token, you must sign it with a private key as described in Creating a Universal Provider Token Signing Key in App Distribution Guide.

The problem is that there is no such section or title or anything in that guide. Perhaps this step is very simple, but not having any hands-on experience with iOS security in particular and little experience with cryptography in general I'm afraid I'll miss something here. I can ask our iOS developers for help but I'm not even sure this approach is mature enough if I can find zero working tutorials.

So, my questions finally are (pick any):

  • Am I missing something and there is a way to follow Apple's guidelines and have the solution be reasonably simple?
  • How likely is it that the binary protocol will be terminated "soon"?
  • Should I choose the binary protocol or HTTP/2?
  • If it's the latter, should I pursue using JWT or is using a certificate more practical?
  • Maybe the situation (mostly with HTTP/2) is much better in some other languages/server platforms? I might even think about having a separate service just for sending iOS pushes done in that if that means jumping through less hoops.

Thank you, sorry for the lengthy text.

  • Asked a question on SO about JWT details I'm missing: JWT for sending iOS push messages from the server – starikoff Oct 28 '16 at 8:26
  • Welcome to the wonderful world of Apple IT services. Easy things are not Apple compliant :-) – Laiv Oct 28 '16 at 19:31
  • The CleverTap library now supports JWT based authentication, just FYI for the others who come across this. Hopefully, with Java 9 out this year, we won't need that ALPN dependency. – judepereira Jan 31 '17 at 6:40
1

We have implemented several push servers and all of them following the old tuple "socket-certificate".In Java (1.5 - 1.7).

To work with certificates has some disadvantages. For instance, we need one for each environment (test, pro, etc). You have to be methodic at managing them or it's quite easy to end up with the wrong cert in pro. Or to forget its renewal (they also expire).

Related to the socket, this approach requires having opened a specific range of ports in the firewall.

Related to the whole protocol of communication. You get so little info after pushing messages. It's hard to figure out what happened with the messages. The only way is to retrieve messages from the queue of responses. A queue which orders is not guaranteed. Neither when APNS is going to put the responses onto it. It might not happen at all.

Compared to GCM (Google cloud message which runs via HTTP), the "socket-cert" of APNS is a pain in the ...

My suggestion is to get focus on the HTTP 2 - JWT protocol. This is a very common implementation of security in client-server communications. You will find many more references about http2 and JWT than looking for APNS sockets and Certs.

Security via JWT is commonly implemented these days. There is full support from the community.

Moreover, If they have planned to drop the support to the current implementation, why even to dare to try it? Why spend time and money twice?

Be preventive. Implementing HTTP2 - JWT approach will save you from further code reviews and refactors. In any case, it's a work to do, so better have it done sooner than later.

Related to the library CleverTap. Well nobody is stopping you from implementing your own client! Suited to your need and requirements.

This has been our case with our current engine. We discarded all the 3rd party implementations and built our own. So far I know it keeps working perfectly... Till Apple drops the service.

(If we didn't move yet to HTTP2 - JWT is due to time and money)

There's perhaps alternatives. Google Firebase Cloud Message is multi-platform. So you can push messages to Android and iOs devices from the same service. It works over HTTP and API keys (tokens). I suggest to you to take a look.

1

There is an alternative way of working with HTTP/2 in Java (alternative to the pains of using JDK-specific jetty alpn-boot jar): using the native SSL provider that supports ALPN. Allows to go without alpn-boot JAR on the bootclasspath completely. Implemented by netty-tcnative (github, docs). Requires that Apache Portable Runtime (APR) be installed. There's a flavour linked against OpenSSL (which must then be installed too and must be of version 1.0.2 or newer), differs for Fedora vs all other Linux distributions. There's a flavour linked statically against BoringSSL (fork of OpenSSL with "reduced code footprint").

Can't be used with Tomcat (because AFAIK it's a partial port of Tomcats tcnative and clashes with it).

My setting that works turned out to be:

  1. Installed APR and OpenSSL.
  2. Specified the pushy library as a dependency (version 0.7.3). It recursively brought alpn-api, parts of netty (4.1.1.Final) and other required dependencies.
  3. Specified netty-tcnative as a dependency (both openssl and boringssl versions worked, chose boringssl so far), version 4.1.1.Final as well.

The pushy library requires usage of a certificate, but JWT support is on the way.

Also, as Laiv has said, GCM (FCM? Firebase?) allows to send pushes to both Android and iOS devices. As far as I understand, for sending to iOS it still requires all Apple-specific parts, the certificate for example, not sure about JWT support. Definitely an option to consider if one doesn't want to implement support for Android and iOS separately.

  • Excatly, Certs are still need it. And yes, It's now Firebase Cloud Message (I have been using GCM for a long while and I get used to say GCM instead of Firebase). The point is to tie your server to Google's protocol (which uses API tokens) and Google does the whole thing around APNS-JWT or whatever APNS need. Often we need to send push notifications but this is just a feature not the business of the system. That's why we started to externalize push notification servers to SaaS solutions instead of implementing our own server. – Laiv Nov 12 '16 at 12:03

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.