Saat pertama kali mendukung Web Push API, Chrome mengandalkan layanan push Firebase Cloud Messaging (FCM), yang sebelumnya dikenal sebagai Google Cloud Messaging (GCM). Hal ini diperlukan menggunakan API eksklusifnya. Hal ini memungkinkan Chrome menyediakan Web Push API bagi developer pada saat spesifikasi Web Push Protocol masih ditulis dan kemudian memberikan autentikasi (yang berarti pengirim pesan adalah orang yang mereka klaim) pada saat Web Push Protocol tidak memilikinya. Kabar baik: tidak ada lagi hal tersebut yang benar.
FCM / GCM dan Chrome kini mendukung Web Push Protocol standar, sedangkan autentikasi pengirim dapat dilakukan dengan menerapkan VAPID, yang berarti aplikasi web Anda tidak lagi memerlukan 'gcm_sender_id'.
Dalam artikel ini, saya akan menjelaskan cara mengonversi kode server yang ada terlebih dahulu untuk menggunakan Web Push Protocol dengan FCM. Selanjutnya, saya akan menunjukkan cara menerapkan VAPID dalam kode klien dan server Anda.
FCM mendukung Web Push Protocol
Mari kita mulai dengan sedikit konteks. Saat aplikasi web Anda mendaftar untuk
langganan push, aplikasi akan diberi URL layanan push. Server Anda akan menggunakan
endpoint ini untuk mengirim data kepada pengguna melalui aplikasi web Anda. Di Chrome, Anda akan
diberi endpoint FCM jika Anda membuat pengguna berlangganan tanpa VAPID. (Kita akan membahas VAPID
nanti). Sebelum FCM mendukung Web Push Protocol, Anda harus mengekstrak ID pendaftaran FCM dari akhir URL dan memasukkannya ke header sebelum membuat permintaan FCM API. Misalnya, endpoint FCM https://android.googleapis.com/gcm/send/ABCD1234
akan memiliki ID pendaftaran 'ABCD1234'.
Setelah FCM mendukung Web Push Protocol, Anda dapat membiarkan endpoint tetap utuh dan menggunakan URL sebagai endpoint Web Push Protocol. (Hal ini selaras dengan Firefox dan semoga semua browser lainnya di masa mendatang.)
Sebelum mempelajari VAPID, kita perlu memastikan kode server kita menangani endpoint FCM dengan benar. Di bawah ini adalah contoh pembuatan permintaan ke layanan push di Node. Perhatikan bahwa untuk FCM, kita menambahkan kunci API ke header permintaan. Untuk endpoint layanan push lainnya, hal ini tidak diperlukan. Untuk Chrome sebelum versi 52, Opera Android, dan Browser Samsung, Anda juga masih harus menyertakan 'hreflang_navigation_id' dalam manifest.json aplikasi web Anda. Kunci API dan ID pengirim digunakan untuk memeriksa apakah server yang membuat permintaan benar-benar diizinkan untuk mengirim pesan ke pengguna penerima.
const headers = new Headers();
// 12-hour notification time to live.
headers.append('TTL', 12 * 60 * 60);
// Assuming no data is going to be sent
headers.append('Content-Length', 0);
// Assuming you're not using VAPID (read on), this
// proprietary header is needed
if(subscription.endpoint
.indexOf('https://android.googleapis.com/gcm/send/') === 0) {
headers.append('Authorization', 'GCM_API_KEY');
}
fetch(subscription.endpoint, {
method: 'POST',
headers: headers
})
.then(response => {
if (response.status !== 201) {
throw new Error('Unable to send push message');
}
});
Ingat, ini adalah perubahan pada API FCM / GCM, sehingga Anda tidak perlu mengupdate langganan. Cukup ubah kode server untuk menentukan header seperti yang ditunjukkan di atas.
Memperkenalkan VAPID untuk identifikasi server
VAPID adalah nama singkat baru yang keren untuk
"Voluntary Application Server Identification". Spesifikasi
baru ini pada dasarnya menentukan handshake antara server aplikasi dan layanan push
serta memungkinkan layanan push mengonfirmasi situs mana yang mengirim pesan.
Dengan VAPID, Anda dapat menghindari langkah-langkah khusus FCM untuk mengirim pesan push. Anda
tidak lagi memerlukan project Firebase, gcm_sender_id
, atau
header Authorization
.
Prosesnya cukup sederhana:
- Server aplikasi Anda membuat pasangan kunci publik/pribadi. Kunci publik diberikan ke aplikasi web Anda.
- Saat pengguna memilih untuk menerima push, tambahkan kunci publik ke objek opsi panggilan subscribe().
- Saat server aplikasi Anda mengirim pesan push, sertakan Token Web JSON yang ditandatangani bersama dengan kunci publik.
Mari kita lihat langkah-langkah ini secara mendetail.
Membuat pasangan kunci publik/pribadi
Saya tidak mahir dalam enkripsi, jadi berikut adalah bagian yang relevan dari spesifikasi terkait format kunci publik/pribadi VAPID:
Server aplikasi HARUS membuat dan mengelola pasangan kunci tanda tangan yang dapat digunakan dengan tanda tangan digital kurva elips (ECDSA) di atas kurva P-256.
Anda dapat melihat cara melakukannya di library node web-push:
function generateVAPIDKeys() {
var curve = crypto.createECDH('prime256v1');
curve.generateKeys();
return {
publicKey: curve.getPublicKey(),
privateKey: curve.getPrivateKey(),
};
}
Berlangganan dengan kunci publik
Untuk membuat pengguna Chrome berlangganan push dengan kunci publik VAPID, Anda harus meneruskan
kunci publik sebagai Uint8Array menggunakan parameter applicationServerKey
dari
metode subscribe().
const publicKey = new Uint8Array([0x4, 0x37, 0x77, 0xfe, …. ]);
serviceWorkerRegistration.pushManager.subscribe(
{
userVisibleOnly: true,
applicationServerKey: publicKey
}
);
Anda akan mengetahui apakah endpoint telah berfungsi dengan memeriksa endpoint dalam objek langganan yang dihasilkan. Jika origin-nya adalah fcm.googleapis.com
, berarti endpoint tersebut berfungsi.
https://fcm.googleapis.com/fcm/send/ABCD1234
Mengirim pesan push
Untuk mengirim pesan menggunakan VAPID, Anda perlu membuat permintaan Web Push Protocol normal dengan dua header HTTP tambahan: header Authorization dan header Crypto-Key.
Header otorisasi
Header Authorization
adalah Token Web JSON (JWT) yang ditandatangani dengan 'WebPush ' di depannya.
JWT adalah cara berbagi objek JSON dengan pihak kedua sedemikian rupa sehingga pihak pengirim dapat menandatanganinya dan pihak penerima dapat memverifikasi tanda tangan dari pengirim yang diharapkan. Struktur JWT adalah tiga string terenkripsi, yang digabungkan dengan satu titik di antaranya.
<JWTHeader>.<Payload>.<Signature>
Header JWT
Header JWT berisi nama algoritma yang digunakan untuk penandatanganan dan jenis token. Untuk VAPID, ini harus:
{
"typ": "JWT",
"alg": "ES256"
}
URL ini kemudian dienkode ke URL base64 dan membentuk bagian pertama dari JWT.
Payload
Payload adalah objek JSON lain yang berisi hal berikut:
- Audiens ("aud")
- Ini adalah origin layanan push (BUKAN origin situs Anda).
Di JavaScript, Anda dapat melakukan hal berikut untuk mendapatkan audiens:
const audience = new URL(subscription.endpoint).origin
- Ini adalah origin layanan push (BUKAN origin situs Anda).
Di JavaScript, Anda dapat melakukan hal berikut untuk mendapatkan audiens:
- Waktu Berakhir Masa Berlaku ("exp")
- Ini adalah jumlah detik hingga permintaan dianggap telah berakhir masa berlakunya. Hal ini HARUS dilakukan dalam waktu 24 jam sejak permintaan dibuat, dalam UTC.
- Subjek ("sub")
- Subjek harus berupa URL atau URL
mailto:
. Hal ini memberikan titik kontak jika layanan push perlu menghubungi pengirim pesan.
- Subjek harus berupa URL atau URL
Contoh payload dapat terlihat seperti berikut:
{
"aud": "http://push-service.example.com",
"exp": Math.floor((Date.now() / 1000) + (12 * 60 * 60)),
"sub": "mailto: my-email@some-url.com"
}
Objek JSON ini dienkode dengan URL base64 dan membentuk bagian kedua JWT.
Tanda Tangan
Tanda Tangan adalah hasil penggabungan header dan payload yang dienkode dengan titik, lalu mengenkripsi hasilnya menggunakan kunci pribadi VAPID yang Anda buat sebelumnya. Hasilnya itu sendiri harus ditambahkan ke {i>header<i} dengan titik.
Saya tidak akan menampilkan contoh kode untuk ini karena ada sejumlah library yang akan mengambil objek JSON header dan payload dan menghasilkan tanda tangan ini untuk Anda.
JWT yang ditandatangani digunakan sebagai header Otorisasi dengan 'WebPush ' ditambahkan di depannya dan akan terlihat seperti berikut:
WebPush eyJ0eXAiOiJKV1QiLCJhbGciOiJFUzI1NiJ9.eyJhdWQiOiJodHRwczovL2ZjbS5nb29nbGVhcGlzLmNvbSIsImV4cCI6MTQ2NjY2ODU5NCwic3ViIjoibWFpbHRvOnNpbXBsZS1wdXNoLWRlbW9AZ2F1bnRmYWNlLmNvLnVrIn0.Ec0VR8dtf5qb8Fb5Wk91br-evfho9sZT6jBRuQwxVMFyK5S8bhOjk8kuxvilLqTBmDXJM5l3uVrVOQirSsjq0A
Perhatikan beberapa hal tentang hal ini. Pertama, header Authorization secara harfiah berisi kata 'WebPush' dan harus diikuti spasi kemudian JWT. Perhatikan juga titik-titik yang memisahkan header, payload, dan tanda tangan JWT.
Header Kunci Kripto
Selain header Otorisasi, Anda harus menambahkan kunci publik VAPID ke
header Crypto-Key
sebagai string yang dienkode URL base64 dengan p256ecdsa=
ditambahkan di awal.
p256ecdsa=BDd3_hVL9fZi9Ybo2UUzA284WG5FZR30_95YeZJsiApwXKpNcF1rRPF3foIiBHXRdJI2Qhumhf6_LFTeZaNndIo
Saat mengirim notifikasi dengan data terenkripsi, Anda akan
sudah menggunakan header Crypto-Key
, jadi untuk menambahkan kunci server
aplikasi, Anda hanya perlu menambahkan titik koma sebelum menambahkan konten di atas, sehingga menghasilkan:
dh=BGEw2wsHgLwzerjvnMTkbKrFRxdmwJ5S_k7zi7A1coR_sVjHmGrlvzYpAT1n4NPbioFlQkIrTNL8EH4V3ZZ4vJE;
p256ecdsa=BDd3_hVL9fZi9Ybo2UUzA284WG5FZR30_95YeZJsiApwXKpNcF1rRPF3foIiBHXRdJI2Qhumhf6_LFTeZaN
Realitas perubahan ini
Dengan VAPID, Anda tidak perlu lagi mendaftar ke akun dengan GCM untuk menggunakan push di Chrome dan Anda dapat menggunakan jalur kode yang sama untuk membuat pengguna berlangganan dan mengirim pesan kepada pengguna di Chrome dan Firefox. Keduanya mengikuti standar.
Yang perlu diingat adalah di Chrome 51 dan sebelumnya, Opera untuk browser Android dan Samsung, Anda masih perlu menentukan gcm_sender_id
di manifes aplikasi web dan Anda harus menambahkan header Otorisasi ke endpoint FCM yang akan ditampilkan.
VAPID menyediakan jalur keluar dari persyaratan eksklusif ini. Jika Anda menerapkan
VAPID, fitur ini akan berfungsi di semua browser yang mendukung push web. Karena semakin banyak browser
yang mendukung VAPID, Anda dapat memutuskan kapan akan menghapus gcm_sender_id
dari
manifes.