How to subscribe to topics with web browser using Firebase Cloud Messaging
I'm trying to find a way to send a notification using Firebase Cloud Messaging to all of my app's users, but I have a web-only app. I've seen solutions that appear to be for Android/iOS, which basically involves having the users auto-subscribe to a topic called "allDevices" and then sending a notification to all users subscribed to that topic. I just can't seem to find any documentation on how to have a web-based user subscribe to a topic. Does anyone know if that's possible, and if it is, is there documentation that I've missed that would cover that?
Thanks!
There is no direct API to subscribe clients to topics in the Firebase Cloud Messaging SDK for JavaScript. Instead you can subscribe a token to a topic through the REST API. Calling this API requires that you specify the FCM server key, which means that you should only do this on a trusted environment, such as your development machine, a server you control, or Cloud Functions. This is necessary, since having the FCM server key allows sending messages on your app's behalf to all of your app's users.
It turns out that in my tests I was using an older project, where client API keys were allows to subscribe to topics. This ability has been removed from newer projects for security reasons.
In Node.js you could for example call the REST API to create a relation mapping for an app instance like this:
function subscribeTokenToTopic(token, topic) {
fetch('https://iid.googleapis.com/iid/v1/'+token+'/rel/topics/'+topic, {
method: 'POST',
headers: new Headers({
'Authorization': 'key='+fcm_server_key
})
}).then(response => {
if (response.status < 200 || response.status >= 400) {
throw 'Error subscribing to topic: '+response.status + ' - ' + response.text();
}
console.log('Subscribed to "'+topic+'"');
}).catch(error => {
console.error(error);
})
}
Where fcm_server_key
is the FCM server key, taken from the Firebase console of your project.
Any one looking for php solution find below since you are going to use Api key of server so don't do this on client side
client side fire base js code
// Initialize Firebase
var config = {
apiKey: "xxxx",
authDomain: "yyy",
databaseURL: "zzzz",
projectId: "aaaa",
storageBucket: "bbbbb",
messagingSenderId: "ccc"
};
firebase.initializeApp(config);
const messaging = firebase.messaging();
messaging.requestPermission()
.then(function() {
console.log('Notification permission granted.');
return messaging.getToken();
})
.then(function(token) {
//send this token to server
console.log(token); // Display user token
})
.catch(function(err) { // Happen if user deney permission
console.log('Unable to get permission to notify.', err);
});
messaging.onMessage(function(payload){
console.log('onMessage',payload);
})
server side code by php curl
$headers = array
('Authorization: key=' . API_ACCESS_KEY,
'Content-Type: application/json');
$ch = curl_init();
// browser token you can get it via ajax from client side
$token = 'drVdtCt82qY:APA91bEZb99GvoS9knv-cp5ThVBiYGBjUwl_Ewj2tKaRFwp7HoG347utaNKbgLWmkxpGadABtIg-DspPUh5sC_bc2JrBKVw10Ejg72nYxZgD2wBU-adYJo0yi03lX22s5K2UEp6gwnMv';
curl_setopt($ch, CURLOPT_URL, "https://iid.googleapis.com/iid/v1/$token/rel/topics/testIshakTopic");
curl_setopt($ch, CURLOPT_POST, true);
curl_setopt($ch, CURLOPT_HTTPHEADER, $headers);
curl_setopt($ch, CURLOPT_POSTFIELDS, array());
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
$result = curl_exec($ch);
echo "The Result : " . $result;
Hope it will help for PHP developers
Franks solution is still valid. However you need to have a server that does the subscribe for you.
function subscribeTokenToTopic(token, topic) {
fetch('https://myserver.com/'+token+'/rel/topics/'+topic, {
method: 'POST',
headers: new Headers({
'Authorization': 'Bearer '+ oauthToken
})
}).then(response => {
if (response.status < 200 || response.status >= 400) {
throw 'Error subscribing to topic: '+response.status + ' - ' + response.text();
}
console.log('Subscribed to "'+topic+'"');
}).catch(error => {
console.error(error);
})
}
then your server has a rest call something like this:
(java spring)
@RequestMapping(value = "/{token}/rel/topics/{topic}", method = RequestMethod.POST)
public ResponseEntity<?> subscribeTokenToTopic(@PathVariable("token") String token, @PathVariable("topic") String topic) throws ServletException {
URL url = new URL("https://iid.googleapis.com/iid/v1/"+token+"/rel/topics/"+topic);
// make https post call here..
...
}
Hopefully that makes sense.
import firebase from 'firebase/app';
import 'firebase/messaging';
const config = {
apiKey: "xxxx",
authDomain: "xxx",
databaseURL: "xxx",
projectId: "xxx",
storageBucket: "xxxx",
messagingSenderId: 'xxxxx',
appId: 'xxxxx',
measurementId: 'xxxxxx'
};
firebase.initializeApp(config);
try {
if (firebase.messaging.isSupported()) {
const messaging = firebase.messaging();
messaging
.getToken({
vapidKey: VAPID_KEY
})
.then((currentToken) => {
if (currentToken) {
subscribeTokenToTopic(currentToken,FirebaseAdminTopic);
}
})
.catch((err) => {
console.log('Error to get token', err);
});
messaging.onMessage((payload) => {
console.log(payload.notification)
});
// Otherwise, we need to ask the user for permission
if (Notification.permission !== 'granted') {
Notification.requestPermission();
}
} else {
console.log('firebase messaging not supported');
}
} catch (err) {
console.log(err);
}
function subscribeTokenToTopic(token, topic) {
fetch(`https://iid.googleapis.com/iid/v1/${token}/rel/topics/${topic}`, {
method: 'POST',
headers: new Headers({
Authorization: `key=${FCM_SERVER_KEY}`
})
})
.then((response) => {
if (response.status < 200 || response.status >= 400) {
console.log(response.status, response);
}
console.log(`"${topic}" is subscribed`);
})
.catch((error) => {
console.error(error.result);
});
return true;
}