Twilio push notification for programmable chat failed - angularjs

I'm working on an app that uses the Twilio Programmable Chat API using node.js and angular js. I have enabled push configuration inside twilio chat instance. And i have created push credentilals in twilio with the firebase secret key. After this i have fetched the twilio token using chatGrant with the twilio credential sid. I have included the firebase.js file and initialised firebase. After this I got permission from user to show notification. This all works fine. But when I am trying to get device token to register with chatclientinstance, it is getting failed.
Here is my code which initialising the firebase and taking permission,
var config = {
apiKey: "my_key",
authDomain: "example.firebaseapp.com",
databaseURL: "https://example.firebaseio.com",
projectId: "example",
storageBucket: "example.appspot.com",
messagingSenderId: "861813283864"
};
if (firebase) {
firebase.initializeApp(config);
console.log("firbase initialized.");
}
if (firebase && firebase.messaging()) {
// requesting permission to use push notifications
firebase.messaging().requestPermission().then(() => {
// getting FCM token
console.log("got permission for showing notification.");
firebase.messaging().getToken().then((fcmToken) => {
// continue with Step 7 here
console.log("got fcm token.",fcmToken);
// ...
// ...
}).catch((err) => {
// can't get token
console.log("error in getting token for notification.",err);
});
}).catch((err) => {
// can't request permission or permission hasn't been granted to the web app by the user
console.log("error in getting permission for notification.",err);
});
} else {
// no Firebase library imported or Firebase library wasn't correctly initialized
console.log("no Firebase library imported or Firebase library wasn't correctly initialized");
}
}
I got this in console,
firbase initialized.
got permission for showing notification.
The script has an unsupported MIME type ('text/html').
Failed to load resource: net::ERR_INSECURE_RESPONSE firebase-messaging-sw.js
error in getting token for notification.
e {code: "messaging/failed-serviceworker-registration", message: "Messaging: We are unable to register the default s…). (messaging/failed-serviceworker-registration).", browserErrorMessage: "Failed to register a ServiceWorker: The script has an unsupported MIME type ('text/html').", stack: "FirebaseError: Messaging: We are unable to registe…o/polyfills.bundle.js:3152:35)↵ at <anonymous>"}
I have did everything as twilio docs says at PUSH NOTIFICATIONS ON WEB
But I did not added "firebase-messaging-sw.js" in my server. Is there any need to add this js file or twilio will automatically create and initialise it?
Please find me a solution for this. Thanks in advance.

I found this confusing too, since the docs don't explain what the notification support actually does. The code you included (from their chat SDK docs) only does two basic things:
client.setPushRegistrationId('fcm', fcmToken) makes sure the browser is registered with the FCM service and requests Twilio Programmable Chat notifications.
messaging.onMessage(function(payload{client.handlePushNotification(payload);}); seems to do very little--it simply lets the Chat client emit an event when FCM receives a message.
What it does not do, though, is create a service that listens for notifications. That's where the missing file comes in. First, create this file, firebase-messaging-sw.js somewhere. I used the following example from the Firebase docs:
// firebase sample code snippets from https://firebase.google.com/docs/cloud-messaging/js/client
importScripts('https://www.gstatic.com/firebasejs/5.0.4/firebase-app.js');
importScripts('https://www.gstatic.com/firebasejs/5.0.4/firebase-messaging.js');
// Initialize the Firebase app in the service worker by passing in the essagingSenderId.
console.log("Initializing service worker...");
firebase.initializeApp({
messagingSenderId: "<FILL IN FROM YOUR FIREBASE CONFIG>"
});
// Retrieve an instance of Firebase Messaging so that it can handle background messages.
var messaging = firebase.messaging();
// Listen for push messages and create notifications
messaging.setBackgroundMessageHandler(function(payload) {
console.log('[firebase-messaging-sw.js] Received background message ', payload);
// Customize notification here
var notificationTitle = "My Notification Title";
var notificationOptions = {
body: "My Notification Text"
};
return self.registration.showNotification(notificationTitle, notificationOptions);
});
This is a basic service worker that listens for notifications and then displays them.
Next, from the error message, you might have noticed that FCM is looking for this file to be served from your web root directory. If that's not the case, tweak your Twilio code slightly to look for this service worker at a specified URL (from https://stackoverflow.com/a/41701594/4006592):
var messaging = firebase.messaging();
if (messaging) {
navigator.serviceWorker.register("<URL FOR firebase-messaging-sw.js>").then(function(registration) {
messaging.useServiceWorker(registration);
// requesting permission to use push notifications
messaging.requestPermission().then(function() {
...
});
});
}
With the above change, you can explicitly specify where firebase-messaging-sw.js is located, and FCM/Twilio Chat will then work as expected.

Related

How to receive notifications from Firebase in window's context (as well as service worker)

I have a react app with the following in firebase-messaging-sw.js in public folder of the app:
importScripts('https://www.gstatic.com/firebasejs/6.3.4/firebase-app.js');
importScripts('https://www.gstatic.com/firebasejs/6.3.4/firebase-messaging.js');
// Initialize the Firebase app in the service worker by passing in the
// messagingSenderId.
firebase.initializeApp({
'messagingSenderId': '<my-sender-id>'
});
// Retrieve an instance of Firebase Messaging so that it can handle background
// messages.
const messaging = firebase.messaging();
messaging.setBackgroundMessageHandler(function(payload) {
console.log('[firebase-messaging-sw.js] Received background message ', payload);
// Do some stuff
});
And in my index.js file I have this:
import * as serviceWorker from './serviceWorker';
if ('serviceWorker' in navigator) {
navigator.serviceWorker.register('../firebase-messaging-sw.js')
.then(function(registration) {
console.log('Registration successful, scope is:', registration.scope);
console.log( registration);
Notification.requestPermission().then((permission) => {
if (permission === 'granted') {
console.log('Notification permission granted.');
// TODO(developer): Retrieve an Instance ID token for use with FCM.
} else {
console.log('Unable to get permission to notify.');
}
});
}).catch(function(err) {
console.log('Service worker registration failed, error:', err);
});
}
I can publish a message and get a notification if the window is not active. So far, so good.
However, I also need to get the notification if the window is active. I try adding this to the service worker:
// Handle incoming messages. Called when:
// - a message is received while the app has focus
// - the user clicks on an app notification created by a service worker
// `messaging.setBackgroundMessageHandler` handler.
messaging.onMessage((payload) => {
console.log('Message received. ', payload);
// ...
});
...but I get this error from firebase:
errors.ts:101 Uncaught FirebaseError: Messaging: This method is available in a Window context. (messaging/only-available-in-window).
It seems that the above javascript needs to go into the index.js file so that it is processed in the window context (all of the questions I have seen on this just say "the onMessage call need to be in the foreground app").
BUT then I don't have access to the messaging variable declared in the service worker.
Whats the correct way to do this? Surely I shouldn't be initialising firebase twice?
Only the setBackgroundMessageHandler()-method must be called in the serviceworker.
You need to use the onMessage() handler in the javascript-files of your Application-UI to do further actions with the payload.
Take a close look at the docs.

TypeError: firebase.auth() is not a function

I am setting a new firebase project. In the project I try to use firebase.auth() to create a new user with user email and password. However, when I use firebase serve and do a post request with the link in postman, i get an error which says firebase.auth is not a function.
I believe that there are questions regarding this issue, however I tried all the solutions that they have provided but none of the worked for me.
I tried:
- Adding require firebase/auth
- Deleting node modules and reinstalling firebase and firebase functions
- Import firebase and functions in different order
- Install firebase and functions in a different order
- Create a new project and install firebase and functions from scratch
const firebase = require('firebase');
const config = {
apiKey: "xxxxx,
authDomain: "xx",
databaseURL: "xxxx",
projectId: "xxxx",
storageBucket: "xxxx",
messagingSenderId: "xxx",
appId: "xxxxxx"
};
firebase.initializeApp(config);
const functions = require('firebase-functions');
const admin = require('firebase-admin');
const app = require('express')();
admin.initializeApp();
//Signup route
app.post('/signup', (req, res) => {
const newUser = {
email: req.body.email,
password: req.body.password,
confirmPassword: req.body.confirmPassword,
handle: req.body.handle,
}
// TODO: validate data
firebase.auth().createUserWithEmailAndPassword(newUser.email, newUser.password)
.then(data => {
return res.status(201).json({ message: `user ${data.user.uid} signed up successfully`})
})
.catch(err => {
console.error(err);
return res.status(500).json({error: err.code});
});
});
Expected results: get status 201 on postman and created new user in firebase
Actual results: TypeError: firebase.auth is not a function. In the console and postman.
You should understand the difference of Firebase JavaScript SDK and Firebase Admin SDK for Node.
The Firebase JavaScript SDK is for the client side.
Firebase Admin SDK is for the server side(like the Cloud Functions).
So in your case, you should use admin.auth().createUser() .
See:
https://firebase.google.com/docs/web/setup
https://firebase.google.com/docs/admin/setup
It seems you want to instantiate the application using the client sdk instead of the server.
You need to use a private key instead, to get one go to your firebase console -> Project Overview -> Service accounts -> Generate new private key
then after you download and include the key in your project:
const admin = require('firebase-admin')
const serviceAccount = require('your_firebase_key/path/goes/here')
admin.initializeApp({
credential: admin.credential.cert(serviceAccount)
})
Good luck!
I was able to resolve this issue by installing firebase as well as firebase-tools. I had initially only installed firebase-tools. Try running npm i firebase, restart the server firebase serve and see if you're still having the issue.

Google API on Published Electron app: gapi.auth2.ExternallyVisibleError: Invalid cookiePolicy

I have a React + Electron app using Google API to authenticate and get a list of calendar events.
The API script is being loaded on the head of my index.html and initialised on my App.js like so:
// Initializes the API client library and sets up sign-in state listeners.
initClient() {
let gapi = window["gapi"];
let that = this;
gapi.load("client", start);
function start() {
gapi.client
.init({
apiKey: GOOGLE_API_KEY,
clientId: CLIENT_ID,
discoveryDocs: [
"https://www.googleapis.com/discovery/v1/apis/calendar/v3/rest"
],
scope: "https://www.googleapis.com/auth/calendar.readonly"
})
.then(() => {
gapi.auth2
.getAuthInstance()
.isSignedIn.listen(that.updateSigninStatus);
that.updateSigninStatus(
gapi.auth2.getAuthInstance().isSignedIn.get()
);
that.setState({
apiLoaded: true
});
});
}
}
It works completely fine on a local environment, where I have a server running, but once I build my Electron app and run the app "natively", I get the following error: gapi.auth2.ExternallyVisibleError: Invalid cookiePolicy
I don't have an advanced understanding of APIs and Servers to figure this out but through research, I found something about the API not working from a "file://" protocol, which is the case on an Electron app.
Thoughts? Ideas?

angularjs express get data back via $http post

I am newbie in firebase admin SDK and trying to get it work on my angularjs app, using and following the steps here and this here:
I have correctly setup my firebase admin SDK and initialized it like this in server.js file on my node server:
var admin = require("firebase-admin");
var serviceAccount = require("path/to/serviceAccountKey.json");
admin.initializeApp({
credential: admin.credential.cert(serviceAccount),
databaseURL: "https://<DATABASE_NAME>.firebaseio.com"
});
app.post('/.firebase-user', function (req, res, nex) {
admin.auth().getUser(req.body.uid)
.then(function (userRecord) {
// See the tables below for the contents of userRecord
console.log("Successfully fetched user data:", userRecord.toJSON());
})
res.status(200).send({data: userRecord.toJSON()});
return nex();
.catch(function (error) {
console.log("Error fetching user data:", error);
res.status(117);
return nex();
});
});
now I want to access userRecord.toJSON() inside my controller:
$http.post('/.firebase-user', {uid: firebase.auth().currentUser.uid})
.then(function(response) {
console.log($scope.data, response.userRecord);
});
But it is not printing the userRecord.toJSON(), instead I get true undefined in the console.
Please help me to fetch the info back inside my app. thanks
It looks like there are a few issues with your (Express) app request handler:
In your Angular code, you make a request to the /.fb endpoint but in your server code you are listener on the /.firebase-user endpoint. I assume you want these to both be the same.
Your server code never actually sends a response to the Angular code. I'm surprised your then() completion handler ever actually completes. You should need to explicitly send a response with something like res.status(200).send(userRecord.toJSON()) in the success case and res.status(400).send({ error: error }) in the error case.
You should add a catch() to your Angular code to ensure you are catching any errors or failed requests being made by the server code.

HTTP request: PUT 401 (Unauthorized)

I start to learn how to use firebase in my app. I follow the instruction in angular website and set the snippet in the index.html like:
<!-- The codes to add firebase -->
<script src="https://www.gstatic.com/firebasejs/3.2.0/firebase.js"></script>
<!-- The core firebase client (required) -->
<script src="https://www.gstatic.com/firebasejs/3.1.0/firebase-app.js"></script>
<!-- firebase-auth - Firebase Authentication (optional) -->
<script src="https://www.gstatic.com/firebasejs/3.1.0/firebase-auth.js"></script>
<!-- firebase-database - The Firebase Realtime Database (optional) -->
<script src="https://www.gstatic.com/firebasejs/3.1.0/firebase-database.js"></script>
<script>
var config = {
apiKey: ...,
authDomain: ...,
databaseURL: "https://...",
storageBucket: "...",
};
firebase.initializeApp(config);
</script>
And then I try to use HTTP request to put data like:
submitForm(personalInfo: PersonalInfo, educationsInfo: Education[], experiencesInfo: Experience[]): Observable<string>{
let body = JSON.stringify({personalInfo, educationsInfo, experiencesInfo});
let headers = new Headers({'Content-Type': 'application/json' });
let options = new RequestOptions({ headers: headers});
console.log(body);
let url = this.firebaseUrl + 'apply-form.json';
return this.http.put(url, body)
.map((response) => {
return response;
})
.catch(this.handleError);
}
However, I got the following error:
PUT https://XXX.firebaseio.com/apply-form.json 401 (Unauthorized)
I don't know what the problem is. I'm new in using firebase and really need someone to help me. Thank you!
Your Firebase Database is by default only writeable by authenticated users. See the warning in the first blue box on the page on saving data to the database.
To work around this you can of course configure the security rules of your database to allow public access. But while that is typically fine during development, it's a bad idea as you get your app ready for release to people other than yourself.
The proper way to post data securely is to require the user to sign in with Firebase Authentication and then use that information to ensure they can only access data that they're authorized to. By using HTTP to access the Firebase Database, you've made this more difficult for yourself than needed. I recommend using the Firebase JavaScript SDK for both authentication and accessing the database.

Resources