Getting issue in generating Firebase token in React JS application - firebase

importScripts("https://www.gstatic.com/firebasejs/9.8.3/firebase-app-compat.js");
importScripts("https://www.gstatic.com/firebasejs/9.8.3/firebase-messaging-compat.js");
// Initialize the Firebase app in the service worker by passing the generated config
const firebaseConfig = {
apiKey: "AIzaSyDk4dYeydr4q3npWx4iqKWejq33r1E",
authDomain: "tengage-33e12.fireeapp.com",
projectId: "tengage-33e12",
storageBucket: "tengage-33e12.appspot.com",
messagingSenderId: "1076165210",
appId: "1:1076165210:web:c9560924940a068ce3",
measurementId: "G-5FMCR8M0G8",
};
firebase.initializeApp(firebaseConfig);
// Retrieve firebase messaging
const messaging = firebase.messaging();
messaging.onBackgroundMessage(function (payload) {
console.log(" message ", payload);
const notificationTitle = payload.notification.title;
const notificationOptions = {
body: payload.notification.body,
};
self.registration.showNotification(notificationTitle, notificationOptions);
});
I have one React js project in which I have to integrate the FCM.
I have added firebase-messaging-sw.js in public folder.
and added the firebbase dependency also.
when I am trying to get token i am getting the error.
SecurityError: Failed to register a ServiceWorker for scope ('http://localhost:3005/') with script ('http://localhost:3005/firebase-messaging-sw.js'): The script has an unsupported MIME type ('text/html').
But with the same firebase credentials when I tried to get the token in the newly created application its giving the token.

The error that is mentioned may occur due to a few reasons , one of which could be an error in the design pattern or syntax. However, it means that any requests for unknown text files initially get redirected to index.html, and therefore return with the MIME type of "text/html", even if it's actually a JavaScript or SVG or some other kind of plaintext file.
Refer below for example:
// Load React App
// Serve HTML file for production
if (env.name === "production") {
app.get("*", function response(req, res) {
res.sendFile(path.join(__dirname, "public""index.html"));
});
}
You may try to add a specific route for service-worker.js before the wildcard route:
app.get("/service-worker.js", (req, res) => {
res.sendFile(path.resolve(__dirname, "public", "service-worker.js"));
});
app.get("*", function response(req, res) {
res.sendFile(path.join(__dirname, "public", "index.html"));
});
Now, when the browser looks for service-worker.js, it will return it with the correct MIME type.
(Note that if you try adding the service-worker.js route after the wildcard, it won't work because the wildcard route will override.)
You also may want to check if the URL http://localhost:3005/firebase-messaging-sw.js, is getting served and its MIME type from the browser interface.
Also , please make sure that the service worker file is generated (Chrome DevTools -> Sources -> Filesystem). You may receive such an error if the above example service-worker.js file is not generated at all (check your deployment script).
You may also refer the links below for more insight:
[1] : https://firebase.google.com/docs/cloud-messaging/js/client#access_the_registration_token
[2] : https://firebase.google.com/docs/cloud-messaging/server
[3] : FCM getToken() Failed to register a ServiceWorker for scope error Flutter web

Related

Recurring SSL protocol error with firebase hosting and cloud functions

I am having an issue with a website I am making for my portfolio. It is hosted on firebase hosting, using the firebase cloud functions for the API calls. my single page react app calls an express router api to query a mongodb database for a list of restaurants. while the firebase emulator is running, I can retrieve the array by going to the api url in my browser, but the web component isn't able to fetch the list and returns an SSL protocol error. Everything I have been able to find so far points to this being a cors issue, but cors() is definitely being use()'d in the server, so I'm a bit lost.
I have tried:
Using the cors npm package in my server, code below:
const functions = require('firebase-functions');
const express = require('express');
const app = express();
const cors = require('cors');
require('dotenv').config({path : './server/config.env'});
const path = require('path');
const publicPath = path.join(__dirname, '..', 'public');
app.use(express.static(publicPath));
app.use(cors());
app.use(express.json());
app.use(require('./server/routes/record'));
exports.api = functions.https.onRequest(app);
Using a mode:cors option in the fetch request: fetch('https://API_URL_HERE', {mode : 'cors'});
Using axios and sending a header with the request: axios.get('https://API_URL', {headers: {'Access-Control-Allow-Origin' : '*'}});
Here is the route I am using as well - I'm using ExpressRouter, not plain Express.js. The problem persisted when I translated it to express.js.
//Returns a list of all restaurants present in the database. The restaurants are objects structured as
// {'name': name,
// 'style': (the type of cuisine),
// 'menu' : (the available items)}
recordRoutes.route('/restaurants').get(async function (req, res) {
console.log('connecting to restaurants db')
await client.connect();
client.db()
.collection('Restaurants')
.find({})
.toArray(function (err, result) {
if (err)
console.log(err);
res.json(result);
});
});
toArray is marked as deprecated in VSC but I can't think of any reason that would be an issue - all the other routes to the database that don't use toArray are nonfunctional.

Firebase App Check with Vue 3 Invalid app resource name

I am trying to get Firebase App Check working in a Vue 3 web app. I have Firebase configured and reCAPTCHA v3 configured.
Here is the code where I initialize Firebase and App Check. I am logging the recaptcha site key to console to make sure the env variables are getting injected correctly.
const fbConfig = {
apiKey: import.meta.env.VITE_APP_FIREBASE_APIKEY,
authDomain: import.meta.env.VITE_APP_FIREBASE_AUTHDOMAIN,
projectId: import.meta.env.VITE_APP_FIREBASE_PROJECTID,
appId: import.meta.env.VITE_APP_FIREBASE_APPID,
storageBucket: import.meta.env.VITE_APP_STORAGEBUCKET,
messagingSenderId: import.meta.env.VITE_APP_MESSAGINGSENDERID,
}
const fbapp = initializeApp(fbConfig)
if (location.hostname === "localhost") {
self.FIREBASE_APPCHECK_DEBUG_TOKEN = true;
}
console.log("APPCHECK Token: ", import.meta.env.VITE_APP_RECAPTCHA_SITEKEY)
const appCheck = initializeAppCheck(fbapp, {
provider: new ReCaptchaV3Provider(import.meta.env.VITE_APP_RECAPTCHA_SITEKEY),
// Optional argument. If true, the SDK automatically refreshes App Check
// tokens as needed.
isTokenAutoRefreshEnabled: true
});
This works as expected on local host where the debug token is used. When I deploy to a live site I get this error.
{ code: 400, message: "Invalid app resource name: \"projects/<name removed>/apps/\"<code removed>\"\".", status: "INVALID_ARGUMENT" }
Any thoughts?
Found the problem. The appId was getting quoted in the environment variables for some reason. Fixing that fixed the issue.

firebase signInWithRedirect with microsoft oauth provider encounters 400 and immediately redirects to original page

I have have an GCP Identity Platform + Firebase app using a Microsoft Active Directory Oauth Provider.
When calling signInWithRedirect it gets a 400 with the url
https://www.googleapis.com/identitytoolkit/v3/relyingparty/createAuthUri?key=<api-key>
(note, I am redacting my specific values)
The payload it sends looks like
{
"providerId": "microsoft.com",
"continueUri": "https://<my-gcp-project-id>.firebaseapp.com/__/auth/handler",
"customParameter": { "tenant": "<my-domain>", "redirect_uri": "http://localhost:3000/callback" }
}
Config
const config = {
apiKey: "<api-key>",
authDomain: "<my-domain>",
};
const firebaseApp = firebase.initializeApp(config);
const firebaseAuthApp = firebaseAuth.getAuth(firebaseApp)
const provider = new firebaseAuth.OAuthProvider('microsoft.com');
provider.setCustomParameters({
tenant: 'mydomain.com',
redirect_uri: 'http://localhost:3000/callback',
});
Triggering auth:
const handleClick = () => {
firebaseAuth.signInWithRedirect(firebaseAuthApp, provider)
}
The issue was an incorrect redirect URI defined in the Azure console Active Directory application configuration.
To get my app working (locally) I provided the firebase auth handler callback:
Reference:
https://learn.microsoft.com/en-us/troubleshoot/azure/active-directory/error-code-aadsts50011-reply-url-mismatch

React Native+Firebase/NodeMailer - Possible Unhandled Promise Rejection

I deployed my Firebase code that sends a test email using this guide, and (finally) successfully invoked the code from within my React Native app by trying to follow the example snippet in the React Native Firebase docs.
However, when I run the function, React Native gives back a Possible Unhanlded Promise Rejection error with the following logs (which shows the detailed Component stack), and I don't receive the test email:
WARN Possible Unhandled Promise Rejection (id: 0):
Error: NOT FOUND
Error: NOT FOUND
http://localhost:8081/index.bundle?platform=ios&dev=true&minify=false&modulesOnly=false&runModule=true&app=org.coreApp2:161257:60
invokePassiveEffectCreate#http://localhost:8081/index.bundle?platform=ios&dev=true&minify=false&modulesOnly=false&runModule=true&app=org.coreApp2:19749:32
invokeGuardedCallbackProd#http://localhost:8081/index.bundle?platform=ios&dev=true&minify=false&modulesOnly=false&runModule=true&app=org.coreApp2:6272:21
invokeGuardedCallback#http://localhost:8081/index.bundle?platform=ios&dev=true&minify=false&modulesOnly=false&runModule=true&app=org.coreApp2:6376:42
flushPassiveEffectsImpl#http://localhost:8081/index.bundle?platform=ios&dev=true&minify=false&modulesOnly=false&runModule=true&app=org.coreApp2:19819:36
unstable_runWithPriority#http://localhost:8081/index.bundle?platform=ios&dev=true&minify=false&modulesOnly=false&runModule=true&app=org.coreApp2:54580:30
http://localhost:8081/index.bundle?platform=ios&dev=true&minify=false&modulesOnly=false&runModule=true&app=org.coreApp2:19604:36
workLoop#http://localhost:8081/index.bundle?platform=ios&dev=true&minify=false&modulesOnly=false&runModule=true&app=org.coreApp2:54531:48
flushWork#http://localhost:8081/index.bundle?platform=ios&dev=true&minify=false&modulesOnly=false&runModule=true&app=org.coreApp2:54506:28
_flushCallback#http://localhost:8081/index.bundle?platform=ios&dev=true&minify=false&modulesOnly=false&runModule=true&app=org.coreApp2:54216:24
_callTimer#http://localhost:8081/index.bundle?platform=ios&dev=true&minify=false&modulesOnly=false&runModule=true&app=org.coreApp2:28655:17
And here are the function logs provided in the Firebase console:
3:56:49.762 PM
sendMail
got here
3:56:55.222 PM
sendMail
{"#type":"type.googleapis.com/google.cloud.audit.AuditLog","status":{},"authenticationInfo":{"principalEmail":"MyEmail#gmail.com"},"serviceName":"cloudfunctions.googleapis.com","methodName":"google.cloud.functions.v1.CloudFunctionsService.UpdateFunction","resourceName":"projects/hb-warranty/locations/us-central1/functions/sendMail"}
In my actual logs, {"principalEmail":"MyEmail#gmail.com"} shows the actually valid Gmail address from my code.
I feel like I'm missing some error handling in my code, and I'm not sure how to debug my code using the current logs.
What changes should be made to my code to improve error handling, and successfully send an email via my Firebase Cloud Function?
Backend Cloud function (/MyApp/functions/index.js):
const functions = require("firebase-functions");
const admin = require('firebase-admin')
const nodemailer = require('nodemailer')
const cors = require('cors')({origin: true});
admin.initializeApp();
let transporter = nodemailer.createTransport({
service: 'gmail',
auth: {
user: 'MyEmail#gmail.com',
pass: 'MyPass'
}
});
console.log('got here');
// exports.sendMail = functions.https.onRequest((req, res) => {
// cors(req, res, () => {
exports.sendMail = functions.https.onCall((data) => {
cors(data, () => {
const dest = data.dest;
const mailOptions = {
from: 'Test Email <MyEmail#gmail.com>',
to: dest,
subject: 'I am squash',
html: `<p style="font-size: 16px;">Squash Richard</p>
<br />
<img src="https://i.etsystatic.com/6129578/r/il/858dbc/703555889/il_570xN.703555889_14z1.jpg" />`
};
return transporter.sendMail(mailOptions, (erro, info) => {
if(erro){
return erro.toString();
}
return 'Sent';
});
});
});
Code from this tutorial. In my actual code, user: MyEmail#gmail.com and from: 'Test Email <MyEmail#gmail.com>' actually use a valid Gmail account, and the account authorizes less secure apps.
Frontend React Native (/MyApp/Email.js):
import React, {useEffect} from 'react';
import { View, Text, StyleSheet } from 'react-native';
import functions from '#react-native-firebase/functions';
function EmailScreen() {
useEffect(() => {
functions().httpsCallable('sendMail')({dest: 'MyOtherEmail#gmail.com'})
})
return(
<View>
<Text>This is the email screen.</Text>
</View>
)
}
export default EmailScreen;
Code from the docs linked above
Gmail uses two factor authentication when Gmail servers doesn't recognize the usual ip address from which the account is accessed from. When deploying to the firebase server this can occur as an issue trying to access your account from a unrecognized ip address. The code will still work running in your local machine. To send transactional emails you have to use sendgrid or zoho mails and there are several other options also

How to request notification permission again on web through flutter

I have integrated notifications for flutter web, its working fine when i give permission for the first time, but lets say user has denied it so is there any way to request notifications permission again to get token in dart files from javascript files ?
importScripts('https://www.gstatic.com/firebasejs/7.15.0/firebase-app.js');
importScripts('https://www.gstatic.com/firebasejs/7.15.0/firebase-messaging.js');
var firebaseConfig = {
apiKey: "",
authDomain: "",
databaseURL: "",
projectId: "",
storageBucket: "",
messagingSenderId: "",
appId: "",
measurementId: ""
};
firebase.initializeApp(firebaseConfig);
const messaging = firebase.messaging();
messaging.setBackgroundMessageHandler(function(payload) {
const notificationTitle = payload.notification.title;
const notificationOptions = {
body: payload.notification.body,
icon: 'favicon.png'
};
return self.registration.showNotification(notificationTitle,
notificationOptions);
});
You can follow a similar permission call posted as an Answer in this post. For your use case, you'll need to use push permission since Firebase Cloud Messaging for web needs Push API support as mentioned in the official docs
Use dart:html package for the permission requests using Web API. Import the dart:html package, and set a prefix. In this sample, we used 'html'
import 'dart:html' as html;
Create a helper method to check for push permissions.
checkPushPermission() async {
var pushPermission = await html.window.navigator.permissions.query({"name": "push"});
print('push permission: ${pushPermission.state}')
}
Call checkPushPermission() to verify the current push permission state, and it should display the relevant permission dialog.
checkPushPermission();
Be reminded that FlutterFire Cloud Messaging is yet to be fully supported for Web, and there could be quirks in its current state. Also, be aware of Web API's browser compatibility.
I did not test it myself but it seems you should call the browser "requestPermission" API:
https://developer.mozilla.org/en-US/docs/Web/API/Notification/requestPermission
https://developer.mozilla.org/en-US/docs/Web/API/Notifications_API/Using_the_Notifications_API
For Flutter I have seen there is this call in "dart:html" package:
https://api.flutter.dev/flutter/dart-html/Notification/requestPermission.html

Resources