Skip to content

Instantly share code, notes, and snippets.

@seunoyeniyi
Created February 18, 2025 08:25
Show Gist options
  • Save seunoyeniyi/fd8aac677a5328487c7551aa8938017b to your computer and use it in GitHub Desktop.
Save seunoyeniyi/fd8aac677a5328487c7551aa8938017b to your computer and use it in GitHub Desktop.
FCM Push Notifications with API only
const jwt = require('jsonwebtoken');
const axios = require('axios');
const fs = require('fs');
function getFCMAccessToken() {
const creds = JSON.parse(process.env.SERVICE_ACCOUNT_JSON || '{}');
const privateKey = creds.private_key.replace(/\\n/g, '\n');
const clientEmail = creds.client_email;
const scopes = ['https://www.googleapis.com/auth/firebase.messaging'];
const url = 'https://oauth2.googleapis.com/token';
const now = Math.floor(Date.now() / 1000);
const payload = {
iss: clientEmail,
sub: clientEmail,
scope: scopes.join(' '),
aud: url,
exp: now + 10,
iat: now,
};
const token = jwt.sign(payload, privateKey, { algorithm: 'RS256' });
return axios.post(url, {
assertion: token,
grant_type: 'urn:ietf:params:oauth:grant-type:jwt-bearer'
}).then(response => response.data.access_token)
.catch(error => {
console.error('Error fetching access token:', error.response?.data || error.message);
return null;
});
}
async function pushFCMByToken(token, title, content, extraData = null, picture = null) {
const apiKey = await getFCMAccessToken();
if (!apiKey) return { code: 'error', message: 'Failed to get access token', data: null };
const projectId = process.env.FIREBASE_PROJECT_ID;
const url = `https://fcm.googleapis.com/v1/projects/${projectId}/messages:send`;
const message = {
message: {
token,
notification: { title, body: content },
data: extraData,
}
};
if (picture) {
message.message.android = { notification: { image: picture } };
message.message.apns = { payload: { aps: { 'mutable-content': 1 } }, fcm_options: { image: picture } };
message.message.webpush = { headers: { image: picture } };
}
try {
const response = await axios.post(url, message, {
headers: { Authorization: `Bearer ${apiKey}`, 'Content-Type': 'application/json' }
});
return { code: 'success', message: 'Notification sent successfully.', data: response.data };
} catch (error) {
return { code: 'error', message: error.response?.data?.message || 'Unable to deliver notification!', data: null };
}
}
async function pushFCMByTopic(topic, title, content, extraData = null, picture = null) {
const apiKey = await getFCMAccessToken();
if (!apiKey) return { code: 'error', message: 'Failed to get access token', data: null };
const projectId = process.env.FIREBASE_PROJECT_ID;
const url = `https://fcm.googleapis.com/v1/projects/${projectId}/messages:send`;
const message = {
message: {
topic,
notification: { title, body: content },
data: extraData,
}
};
if (picture) {
message.message.android = { notification: { image: picture } };
message.message.apns = { payload: { aps: { 'mutable-content': 1 } }, fcm_options: { image: picture } };
message.message.webpush = { headers: { image: picture } };
}
try {
const response = await axios.post(url, message, {
headers: { Authorization: `Bearer ${apiKey}`, 'Content-Type': 'application/json' }
});
return { code: 'success', message: 'Notification sent successfully.', data: response.data };
} catch (error) {
return { code: 'error', message: error.response?.data?.message || 'Unable to deliver notification!', data: null };
}
}
module.exports = { getFCMAccessToken, pushFCMByToken, pushFCMByTopic };
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment