I implement web notification feature in React + Firebase. Although successfully get a web notification token, but the error occurs when sending with Firebase Cloud Messaging.
The error belows:
Messaging: A problem occured while subscribing the user to FCM: Request is missing required authentication credential. Expected OAuth 2 access token, login cookie or other valid authentication credential. See https://developers.google.com/identity/sign-in/web/devconsole-project.
Firebase code(React):
import * as firebase from 'firebase/app'
import 'firebase/analytics'
import 'firebase/auth'
import 'firebase/database'
import 'firebase/firestore'
import 'firebase/functions'
import 'firebase/storage'
import 'firebase/messaging'
const firebaseConfig = {
apiKey: process.env.REACT_APP_FIREBASE_API_KEY,
authDomain: process.env.REACT_APP_FIREBASE_AUTH_DOMAIN,
databaseURL: process.env.REACT_APP_FIREBASE_DATABASE_URL,
projectId: process.env.REACT_APP_FIREBASE_PROJECT_ID,
storageBucket: process.env.REACT_APP_FIREBASE_STORAGE_BUCKET,
messagingSenderId: process.env.REACT_APP_FIREBASE_MESSAGING_SENDER_ID,
appId: process.env.REACT_APP_FIREBASE_APP_ID,
measurementId: process.env.REACT_APP_FIREBASE_MEASUREMENT_ID,
}
// Initialize Firebase
firebase.initializeApp(firebaseConfig)
firebase.analytics()
// comment out when debug
// firebase.firestore.setLogLevel('debug')
export const database = firebase.database()
export const firestore = firebase.firestore()
export const functions = firebase.functions()
export const storage = firebase.storage()
// comment out when use emulator
// functions.useFunctionsEmulator('http://localhost:5001')
export default firebase
firestore
.doc(`users/${currentUserUid}`)
.get()
.then((userDocSnap) => {
if (!userDocSnap.exists) return
if (userDocSnap.data().webNotification) return
if (firebase.messaging.isSupported()) {
const messaging = firebase.messaging()
messaging.usePublicVapidKey(
process.env.REACT_APP_FIREBASE_PUBLIC_VALID_KEY,
)
messaging
.requestPermission()
.then(() => {
messaging
.getToken()
.then((token) => {
userDocSnap.ref.update({
webNotification: token,
})
})
.catch((err) => {
console.log('Failed to get token', err)
})
})
.catch((err) => {
console.log("Can't get permission", err)
})
}
})
Push notification(function)
const sendWebNotification = (data) => {
try {
const headers = {
headers: {
'Content-Type': 'application/json',
Authorization: 'Bearer ' + webApiKey,
},
}
axios
.post('https://fcm.googleapis.com/fcm/send', data, headers)
.catch((err) => {
console.log('Error:', err)
})
} catch (error) {
console.log(error)
}
}
Related
I am trying to integrate firebase cloud messaging for notifications, I have added a firebase configure file in App.js and add a service worker (firebase-messaging-sw.js) file in the root (public folder).
while heating an API "https://fcm.googleapis.com/fcm/send", I am getting a message, but it only receives in the background and in the notification, it is not sowing any data, that I have sent by API, It sends just a message "The site has been updated in the background"
file app.js
const firebaseConfig = {
apiKey: "AIz.........................",
authDomain: "firebase project",
projectId: "projectId......",
storageBucket: "storageBucket........",
messagingSenderId: "5487851245788....",
appId: "546497946497995....",
measurementId: "D-54646464646446",
};
const app = initializeApp(firebaseConfig);
const messaging = getMessaging(app);
console.log("messaging: ", messaging)
const VapidKey = "BK08o6mE9WMPK5Wovhkn-..............."
const subscribe = () => {
Notification.requestPermission().then((permission) => {
console.log("permission: ", permission);
if (permission === "granted") {
firebaseToken(messaging, { vapidKey: VapidKey }).then((currentToken) => {
console.log("CurrentToken firebase: ", currentToken);
storeFirebaseToken(currentToken)
}).catch((err) => {
console.log("err: ", err)
})
}
})
}
useEffect(() => {
subscribe();
}, [])
file firebase-messaging-sw.js
import { initializeApp } from "firebase/app";
import { getMessaging, onMessage} from "firebase/messaging/sw";
import { onBackgroundMessage } from "firebase/messaging/sw";
const firebaseConfig = {
apiKey: "AIz.........................",
authDomain: "firebase project",
projectId: "projectId......",
storageBucket: "storageBucket........",
messagingSenderId: "5487851245788....",
appId: "546497946497995....",
measurementId: "D-54646464646446",
};
const app = initializeApp(firebaseConfig);
const messaging = getMessaging(app);
onBackgroundMessage(messaging, (payload) => {
console.log('[firebase-messaging-sw.js] Received background message ', payload);
// Customize notification here
const notificationTitle = 'Background Message Title';
const notificationOptions = {
body: 'Background Message body.',
icon: '/firebase-logo.png'
};
// self.registration.showNotification(notificationTitle,
// notificationOptions);
});
onMessage(messaging, (payload) => {
console.log('Message received. ', payload);
// ...
});
I have added Onmessage and background methods in firebase-messaging-sw.js file, but I am not getting in that method,
I am expecting to receive a notification with title and icon and want to implement a click function on that
I'm having trouble setting up my firebase environment in React.
I'm going through the firebase documentation, but I can't seem to get the first step of getting permission correct.
I tried looking everywhere to fix these errors, but all attempts failed. Please help!
Errors:
Service worker registration failed, error: TypeError: Failed to register a ServiceWorker for scope ('http://localhost:8080/') with script ('http://localhost:8080/firebase-messaging-sw.js'): A bad HTTP response code (404) was received when fetching the script.
An error occurred while retrieving token. FirebaseError: Messaging: We are unable to register the default service worker. Failed to register a ServiceWorker for scope ('http://localhost:8080/firebase-cloud-messaging-push-scope') with script ('http://localhost:8080/firebase-messaging-sw.js'): A bad HTTP response code (404) was received when fetching the script. (messaging/failed-service-worker-registration).
Code:
src/index.js
if ('serviceWorker' in navigator) {
navigator.serviceWorker.register('../firebase-messaging-sw.js')
.then(function(registration) {
console.log('Registration successful, scope is:', registration.scope);
}).catch(function(err) {
console.log('Service worker registration failed, error:', err);
});
}
src/firebase.js
import { initializeApp } from "firebase/app";
import { getMessaging, getToken } from "firebase/messaging";
const firebaseApp = initializeApp({
apiKey: "",
authDomain: "",
projectId: "",
storageBucket: "",
messagingSenderId: "",
appId: "",
measurementId: ""
});
const messaging = getMessaging(firebaseApp);
export const fetchToken = async (setToken) => {
await getToken(messaging, { vapidKey: KEY_PAIR }).then((currentToken) => {
if (currentToken) {
setToken(currentToken)
} else {
console.log('No registration token available. Request permission to generate one.');
}
}).catch((err) => {
console.log('An error occurred while retrieving token. ', err);
});
}
public/firebase-messaging-sw.js
import { initializeApp } from "firebase/app";
import { getMessaging, onBackgroundMessage } from "firebase/messaging/sw";
const firebaseApp = initializeApp({
apiKey: "",
authDomain: "",
projectId: "",
storageBucket: "",
messagingSenderId: "",
appId: "",
measurementId: ""
});
const messaging = getMessaging(firebaseApp);
onBackgroundMessage(messaging, (payload) => {
console.log('[firebase-messaging-sw.js] Received background message ', payload);
// Customize notification here
const notificationTitle = 'Background Message Title';
const notificationOptions = {
body: 'Background Message body.',
icon: ''
};
self.registration.showNotification(notificationTitle, notificationOptions);
});
so I did this a few months ago and it worked for me, it should for you as well...
First you need to register de service worker to ger this running so in your index.js you can do the following:
// IMPORTS...
if ("serviceWorker" in navigator) {
navigator.serviceWorker
.register("../firebase-messaging-sw.js")
.then(function (registration) {
console.log("Registration successful, scope is:", registration.scope);
})
.catch(function (err) {
console.log("Service worker registration failed, error:", err);
});
}
const dashboard = (
<Provider store={MyStore}>
<PersistGate loading={null} persistor={persistor}>
<BrowserRouter>
<App />
</BrowserRouter>
</PersistGate>
</Provider>
);
ReactDOM.render(dashboard, document.getElementById("root"));
reportWebVitals();
Then the sw firebase register looks like this:
importScripts("https://www.gstatic.com/firebasejs/9.0.0/firebase-app-compat.js");
importScripts("https://www.gstatic.com/firebasejs/9.0.0/firebase-messaging-compat.js");
firebase.initializeApp({
apiKey: "",
authDomain: "",
projectId: "",
storageBucket: "",
messagingSenderId: "",
appId: "",
measurementId: "",
});
const isSupported = firebase.messaging.isSupported();
if (isSupported) {
const messaging = firebase.messaging();
messaging.onBackgroundMessage(({ notification: { title, body, image } }) => {
self.registration.showNotification(title, {
body,
icon: image || "/assets/icons/icon-72x72.png",
});
});
}
It is important to have a config file for firebase: firebase.js
import { initializeApp } from "firebase/app";
import { getMessaging, getToken } from "firebase/messaging";
const firebaseConfig = {
apiKey: process.env.REACT_APP_FIREBASE_API_KEY,
authDomain: process.env.REACT_APP_FIREBASE_AUTH_DOMAIN,
projectId: process.env.REACT_APP_FIREBASE_PROJECT_ID,
storageBucket: process.env.REACT_APP_FIREBASE_STORAGE_BUCKET,
messagingSenderId: process.env.REACT_APP_FIREBASE_MESSENGER_SENDER_ID,
appId: process.env.REACT_APP_FIREBASE_APP_ID,
measurementId: process.env.REACT_APP_FIREBASE_MEASUREMENT_ID,
};
const firebaseApp = initializeApp(firebaseConfig);
const messaging = getMessaging(firebaseApp);
export { firebaseApp };
export const fetchToken = async (setToken) => {
await getToken(messaging, {
vapidKey: "KEY",
})
.then((currentToken) => {
if (currentToken) {
// setToken(currentToken);
console.log("currentToken: ", currentToken);
} else {
console.log("No registration token available. Request permission to generate one.");
}
})
.catch((err) => {
console.log("An error occurred while retrieving token. ", err);
});
};
After these files configures you can call the fetchToken function from a useEffect inside your main file/navigator/etc and then you can use the onMessage hook/function from firebase/messaging itself
Hi I have Web based fcm setup using django and plain html
I Have refer this https://firebase.google.com/docs/cloud-messaging/js/receive#handle_messages_when_your_web_app_is_in_the_foreground
HTML
import { initializeApp } from "https://www.gstatic.com/firebasejs/9.0.2/firebase-app.js";
import { getAnalytics } from "https://www.gstatic.com/firebasejs/9.0.2/firebase-analytics.js";
import { getMessaging, getToken, onMessage } from "https://www.gstatic.com/firebasejs/9.0.2/firebase-messaging.js";
const firebaseConfig = {
apiKey: "",
authDomain: "",
projectId: "",
storageBucket: "",
messagingSenderId: "",
appId: "",
measurementId: ""
};
const app = initializeApp(firebaseConfig);
const analytics = getAnalytics(app);
const messaging = getMessaging();
// THIS IS NOT WORKING
onMessage(messaging, (payload) => {
console.log('Message received. ', payload);
console.log('Message received. ', payload);
console.log('Message received. ', payload);
});
getToken(messaging, { vapidKey: '' }).then((currentToken) => {
if (currentToken) {
console.log('11111111')
console.log(currentToken)
console.log(currentToken)
} else {
console.log('222222222')
// Show permission request UI
console.log('No registration token available. Request permission to generate one.');
// ...
}
}).catch((err) => {
console.log('An error occurred while retrieving token. ', err);
// ...
});
I am signing in user using mobile number and then i want him to enter email and password later. (after logging in)
I am trying to link email,password Auth method to current PhoneAuth method.
But it's giving me an error:
Cannot read property 'link' of undefined
Here is code:
import { firebaseAuth,fire, messaging } from '../../config/constants';
var credential = fire.auth.EmailAuthProvider.credential(email, password);
fire.auth.currentUser.link(credential).then(function(user) {
console.log("Account linking success", user);
}, function(error) {
console.log("Account linking error", error);
});
And in config/constants
import firebase from 'firebase'
require("firebase/firestore");
const config = {
apiKey: "AIzxxxxxxxxxxxxxxxxxxKXI",
authDomain: "payxxxxxxxxxxxxja1.firebaseapp.com",
databaseURL: "https://payxxxxxxxxxxja1.firebaseio.com",
projectId: "payxxxxxxxxxxxxja1",
storageBucket: "payxxxxxxxxxxxja1.appspot.com",
messagingSenderId: "281xxxxx5xxxxx6"
}
firebase.initializeApp(config)
export const fire = firebase
export const ref = firebase.database().ref()
export const firebaseAuth = firebase.auth
export const messaging = firebase.messaging();
I think something is wrong with fire.auth or fire.auth()
Thanks
link has been removed in favor of linkWithCredential starting with Firebase JS version 4.0.0: https://firebase.google.com/support/release-notes/js#4.0.0
Also make sure the current user is ready:
firebase.auth().onAuthStateChange(user => {
if (user) {
// currentUser is not null.
} else {
// currentUser is null.
}
});
I am trying to link email,password Auth method to current PhoneAuth method.
But it's giving me an error:
Cannot read property 'link' of undefined
Here is code:
import { firebaseAuth,fire, messaging } from '../../config/constants';
var credential = fire.auth.EmailAuthProvider.credential(email, password);
fire.auth.currentUser.link(credential).then(function(user) {
console.log("Account linking success", user);
}, function(error) {
console.log("Account linking error", error);
});
And in config/constants
import firebase from 'firebase'
require("firebase/firestore");
const config = {
apiKey: "AIzxxxxxxxxxxxxxxxxxxKXI",
authDomain: "payxxxxxxxxxxxxja1.firebaseapp.com",
databaseURL: "https://payxxxxxxxxxxja1.firebaseio.com",
projectId: "payxxxxxxxxxxxxja1",
storageBucket: "payxxxxxxxxxxxja1.appspot.com",
messagingSenderId: "281xxxxx5xxxxx6"
}
firebase.initializeApp(config)
export const fire = firebase
export const ref = firebase.database().ref()
export const firebaseAuth = firebase.auth
export const messaging = firebase.messaging();
Please help me through this. Thanks
Following is what they have mentioned in there Docs.
Pass the AuthCredential object to the signed-in user's
linkWithCredential method:
auth.currentUser.link(credential).then(function(user) {
console.log("Account linking success", user);
}, function(error) {
console.log("Account linking error", error);
});
And following is what resolves the problem.
auth.currentUser.linkWithCredential(credential).then(function(user) {
console.log("Account linking success", user);
}, function(error) {
console.log("Account linking error", error);
});
Simply replacing link with linkWithCredential made it working. That is how dumb the Doc writer is.