An error occurred when trying to authenticate to the FCM servers - firebase

An error occurred when trying to authenticate to the FCM servers. Make sure the credential used to authenticate this SDK has the proper permissions. See https://firebase.google.com/docs/admin/setup for setup instructions
enter image description here

For solving this problem I took the following steps:
open Google Cloud Platform Dashboard
Go to API and Services
Enable API and Services
Search for Cloud Messaging
Turn on the cloud messaging and Firebase cloud messaging API.

I just came across this issue and, for me, it was because I was using a simulator.
The FCM token generated by the simulator isn't valid for firebase cloud messaging and it was throwing this error.
I put my admin.messaging().sendToDevice() into a try catch and it's working fine.
I don't know if is sends the notification only to the valid tokens or if it totally ignores all of them though

Download a new private key and delete the old one!

By default Firebase uses Firebase Cloud Messaging API (V1) so you need to use this api instead of legacy one
for Firebase Cloud Messaging API (V1) :
const data = {
message: {
token: registrationToken,
notification: {
title: "Notification Title",
body: "Notification Body ",
},
data: {
Nick: "Mario",
Room: "PortugalVSDenmark",
},
},
};
admin.messaging().send(data.message);
for Cloud Messaging API (Legacy)
1.First go to Google Cloud Platform Dashboard and enable Cloud Messaging Service
2. and then you can use like this :
var payload = {
notification: {
title: "This is a Notification",
body: "This is the body of the notification message.",
},
};
var options = {
priority: "high",
};
var registrationToken ="your device token";
admin
.messaging()
.sendToDevice(registrationToken, payload, options)
.then(function (response) {
console.log("Successfully sent message:", response);
})
.catch(function (error) {
console.log("Error sending message:", error);
});
Firebase Cloud Messaging API (V1) is recommended than Cloud Messaging API (Legacy)

In my case, following Abhimanyu's solution to generate a new key still couldn't solve the problem.
After digging for 5 hours, I found the root cause that Google didn't activate this API for my project!!!!
It works After I activate the Cloud Messaging permission.

Just to clarify the FCM v1 usage as pointed by #Abhishek Ghimire.
Here is how to create the message:
const message = {
token: registrationToken,
notification: {
title: "Notification Title",
body: "Notification Body ",
},
};
admin.messaging().send(message);

Related

Verifying reCAPTCHA v3 in Firebase Function causes CORS Issue

I have the following codes that verify Google reCAPTCHA v3 in my Firebase Function that caused the CORS issue:
const functions = require('firebase-functions');
const nodemailer = require("nodemailer");
const express = require("express");
const cors = require("cors");
const request = require('request');
const serverApi = express();
api.use(cors({ origin: true }));
function verifyCaptcha(token, returnData) {
// Put your secret key here.
var secretKey = functions.config().recaptcha.secretkey;
var verificationUrl = "https://www.google.com/recaptcha/api/siteverify?secret=" + secretKey + "&response=" + token;
// Note here: External network call to google.com
request(verificationUrl, function (error, response, body) {
body = JSON.parse(body);
// Success will be true or false depending upon captcha validation.
if (!body.success) {
body['status'] = false;
body['errSource'] = "recaptcha";
body['message'] = "Failed to pass captcha verification.";
} else {
body['status'] = true;
body['message'] = "Successfully passed captcha verification!";
};
console.log(`Google returns: ${JSON.stringify(body)}`);
returnData(body);
});
};
api.post("/api/service-name", (req, res) => {
if (!req.body['g-recaptcha-response']) {
return res.send({ "status": false, "errSource": "recaptcha", "message": "Client-side reCAPTCHA token not found." });
};
const recaptchaToken = req.body['g-recaptcha-response'];
verifyCaptcha(recaptchaToken, function (result) {
if (result.status == false) {
return res.send(result);
};
// My business logics here.
});
});
exports.api = functions.https.onRequest(api);
I noticed that after removing the reCAPTCHA v3 verification request in within my Firebase Function, no more CORS issue for my localhost to call "/api/service-name" using $.ajax(). This is because the following Firebase Function log reminded me of the "External network is not accessible":
Billing account not configured. External network is not accessible and quotas are severely limited.
Configure billing account to remove these restrictions
My question is: Is there a way to get my server-side reCAPTCHA verification to work without causing this CORS issue, which could be prevented by "Billing account not configured"? Thanks!
UPDATE:
After catching the request() error that does the verification, I get the following error:
{errno: "EAI_AGAIN", code: "EAI_AGAIN", syscall: "getaddrinfo", hostname: "www.google.com", host: "www.google.com", …}
Also, after handling this error, no more CORS issue, but reCAPTCHA still cannot be verified. Any idea what causes this? Thanks again!
It's now confirmed that the above issue has been resolved after Enable Billing at the Google Cloud Console. It is NOT actually the CORS issue between the localhost and Firebase Functions/Hosting (although the Chrome browser returned as CORS related error message), it's actually the HTTP Request from the Firebase Function to the Google reCAPTCHA api during token verification process. Due to billing account not linked to the Firebase Project where the function sits in, any requests from any Firebase Functions to any External Network Resources, including Google reCAPTCHA, will be rejected with the following errors:
HTTP Request Error:
{errno: "EAI_AGAIN", code: "EAI_AGAIN", syscall: "getaddrinfo", hostname: "www.google.com", host: "www.google.com", …}
After enabling billing at GCP and linking the billing account to the specific Firebase Project, the request to Google reCAPTCHA verification will be successful (if the token is valid) without the above error. However, your FREE Spark Tier Firebase account will be AUTOMATICALLY UPGRADED to Blaze Plan -- Pay as you go.

Programmatically add Google Analytics to Firebase project

I wish to automate all of the steps involved in setting up a new Firebase project without any user interaction. I've accomplished most of the steps via either the gCloud CLI, Firebase CLI or the GoogleApis NodeJS library.
Authentication has been done via the CLI tools or via service accounts.
The only thing I haven't been able to do so far is adding Google Analytics to the newly created Firebase project. I have found this Google Api which should accomplish this, but I'm having problems authenticating the request.
How would I authenticate a request to this API without any user interaction? The API is not available via the CLI tools, so my best guess would be to use a service account with the owner IAM-role, but the request keeps failing.
My steps so far have been:
Ensuring that the management API is enabled
Add a service account to the GCloud project with owner privileges
Download the service account
Run the following code
import { google } from 'googleapis';
import * as fetch from 'node-fetch';
async function addGoogleAnalytics {
const token = await getJWTAcessToken();
await addAnalyticsFetch(token);
};
async function addAnalyticsFetch(accessToken) {
const url = `https://firebase.googleapis.com/v1beta1/projects/<my-project-id>:addGoogleAnalytics`;
const fetchResult = await fetch(url, {
method: 'POST',
headers: { Authorization: `Bearer ${accessToken}` },
json: true,
body: JSON.stringify({ analyticsAccountId: '<my-analytics-account-id>' }),
});
const fetchResultText = await fetchResult.text();
console.log('Fetch result: ', fetchResultText);
}
function getJWTAcessToken() {
const SCOPES = ['https://www.googleapis.com/auth/cloud-platform'];
const key = require('../../serviceAccount.json');
return new Promise((resolve, reject) => {
const jwtClient = new google.auth.JWT(key.client_email, null, key.private_key, SCOPES, null);
jwtClient.authorize((err, tokens) => {
if (err) {
reject(err);
return;
}
resolve(tokens.access_token);
});
});
}
The result of the API call is a simple 403 - "The caller does not have permission".
I've also attempted this using the GoogleApis NodeJS library with similar results.
If being a project owner doesn't give enough privileges, how do I permit this service account to perform this API call? I have a suspicion that I'm failing because the service account is in no way associated with the Google Analytics account, but the documentation doesn't list that as a requirement. It is also not listed as a step in Google's own guide.
It turns out that the above code is 100 % valid. The problem was indeed that the service account had enough privileges to edit the Firebase-project, but it had no authorization to create a new property for the Google Analytics account.
After giving the service account edit privileges for the Google Analytics account, the connection between Firebase and Google Analytics was successfully established. This process can be automated via this API.

How to send SMS programmatically using Amazon Amplify SDK for my Android app users?

I want to send a welcome message (SMS) to phone number of my app's user when they will sign up using their phone number. I couldn't find official documentation for this particular task.
Amazon lets you do this. Assuming you're using Cognito for sign-up, you'll want to use the post-confirmation Cognito lambda trigger.
Set up your SNS account via the AWS Console, to send SMS messages. Send yourself a test message via the console.
Run amplify auth update
When it gets to the question Do you want to configure Lambda Triggers for Cognito?, answer Yes and choose the Post Confirmation trigger
You need to grant SNS (SMS) permissions to the lambda. Update the PostConfirmation-cloudformation-template.json file to add a new statement under Resources.lambdaexecutionpolicy.Properties.PolicyDocument.Statement:
{
"Resources": {
"lambdaexecutionpolicy": {
"Properties": {
"PolicyDocument": {
"Statement": [
{
"Effect": "Allow",
"Action": "sns:*",
"Resource": "*"
}
]
...
}
...
}
...
}
...
}
...
}
Use this code for the trigger:
var aws = require('aws-sdk');
var sms = new aws.SNS();
exports.handler = (event, context, callback) => {
console.log(event);
if (event.request.userAttributes.phone_number) {
sendSMS(event.request.userAttributes.phone_number, "Congratulations " + event.userName + ", you have been confirmed: ", function (status) {
// Return to Amazon Cognito
callback(null, event);
});
} else {
// Nothing to do, the user's phone number is unknown
callback(null, event);
}
};
function sendSMS(to, message, completedCallback) {
const params = {
Message: message, /* required */
PhoneNumber: to
};
sns.publish(params, function (err, data) {
if (err) {
console.log(err, err.stack); // an error occurred
} else {
console.log(data);
}
completedCallback("SMS Sent");
})
};
Not sure if sending SMS is a service, Amazon Amplify provides.
But you could use a service like Twilio to send SMS (and much more) to phones.
AWS Amplify can help you setting up SMS, Email and Push notifications to your users by integrating with Amazon Pinpoint. Take a look at the documentation here: https://aws-amplify.github.io/docs/js/push-notifications.
Amazon Pinpoint allows you to create user segmentation, message templates, campaigns (with A/B testing and canary as well), Journeys (for email only so far), and so many more other things. You can integrate it and configure it using AWS Amplify, but some of those features I've mentioned are still not supported by AWS Amplify and you will have to either use the AWS Console to configure or use the AWS SDK to integrate with your app. You can leverage the AWS Amplify Auth module in order to get a valid Cognito token which will allow you to interact with Amazon Pinpoint directly.

Firebase client error: Custom token corresponds to a different audience

I'm using the Firebase Python AdminSDK to generate a custom token which a Javascript client uses to sign in to Firebase. When the JS client tries to authenticate with the custom token it gets the error "Custom token corresponds to a different audience".
The code given with the error: 'auth/custom-token-mismatch'.
Many Google'd answers regarding the "audience" mismatch reference Analytics. But I'm doing a Web project, not iOS or Android, so I can't use Analytics to manage audiences.
The SO answers I've read are listed at the end, below.
I captured the custom token and plugged it in to https://jwt.io/ and both the values and the instanciation/expiration times (an hour apart) look good:
Decoded custom token on jwt.io:
{
"claims": {},
"uid": "<myuniqueID",
"sub": "firebase-adminsdk-1knpr#firebase-<myproject>.iam.gserviceaccount.com",
"iss": "firebase-adminsdk-1knpr#firebase-<myproject>.iam.gserviceaccount.com",
"iat": 1540153710,
"aud": "https://identitytoolkit.googleapis.com/google.identity.identitytoolkit.v1.IdentityToolkit",
"exp": 1540157310
}
Python server:
def getFirebaseInstance(): # For Firebase Python SDK
try:
currentDir_path = os.path.dirname(os.path.realpath(__file__))
cred = credentials.Certificate(currentDir_path + '/includeFirebaseServiceAccounts/firebase-<myprojectname>-firebase-adminsdk-1knpr-e1244dd261.json')
firebaseAdmin = firebase_admin.initialize_app(cred, { 'databaseURL': 'https://<myprojectname>.firebaseio.com', 'databaseAuthVariableOverride': {'uid':'<myuniqueServerID>'}})
if firebaseAdmin:
return(firebaseAdmin)
except:
raise
def firebaseClientToken(request):
try:
uid = "<myuniqueClientID>" # case sensitive
additional_claims = { }
token = auth.create_custom_token(uid,additional_claims)
return HttpResponse(token)
except Exception as err:
return HttpResponse("System error:" + str(err), status=406)
Javascript client:
(
function authClient2Firebase() {
$.ajax({
url: "firebaseClientToken/",
method: "POST",
success: function(response) { step2(response); },
error: function(xhr) { alert("There was an error loading a security check. Have you lost your internet connection? Detail:" + xhr.responseText); }
});
function step2(customToken) {
try {
firebase.auth().signInWithCustomToken(customToken).catch(function(error) {
var errorCode = error.code;
var errorMessage = error.message;
alert("There was an error with the secure login. \n\nDetail: " + errorMessage + '\nCode: ' + errorCode);
});
}
catch(err) {
alert(err);
}
console.log("authClient2Firebase.js: Firebase login succeeded!");
}
}
)();
My project under the Console "Settings" page does have a Web API key, but I don't see anywhere that it's used.
There's only one user, me, under the Console's "Settings"->"Users and Permissions" page.
There's only one service account listed on the Console "Settings"->"Service Accounts" page. I tried deleting all secrets on that page, generating a new one, then generating and installing a new blue-button "secret" (bad name, actually it generates a whole json credential object).
These are the domains listed in Console "Authentication" -> "Sign-in Method":
localhost Default
<myproject>.firebaseapp.com Default
127.0.0.1 Custom
auth.firebase.com Custom
The actual domain I'm using is localhost:8000, which can't be entered here.
SO answers consulted unsuccessfully:
The custom token corresponds to a different audience
(I'm not using a key, except what's stored in the ServiceAccount
credentials.)
Firebase token error, "The custom token corresponds to a different audience."
Firebase custom auth issue token different audienceenter
link description here (Close, but I'm not using a Node server and
not sure what he means by server "must belong to the same project"
since the Python server isn't registered in any way except through the
ServiceAccount credentials which I downloaded.)
Embarrassing but true, it turned out to be a simple oversight. When the JS client initialized itself as a Firebase app, before authenticating, it was using old credentials from a test environment.
// Initialize Firebase
var config = {
apiKey: "<WebAPI from Firebase console, 'Project Settings'>",
authDomain: "<myproject>.firebaseapp.com",
databaseURL: "https://<myproject>.firebaseio.com",
projectId: "<myproject>",
storageBucket: "<myproject>.appspot.com",
messagingSenderId: "<id from Console Project Settings>" // optional
};
firebase.initializeApp(config);

Firebase Cloud Messaging for web

I want to build a messaging app for web using Google's Firebase. In this app, a user should send and receive messages to/from other users. I checked Google's Firebase website but I got lost. Can you tell me where to start? Can you show me any tutorial or something like that related to Firebase web messaging? I welcome any suggestions. Thanks.
Firebase Cloud Messaging for Web is now officially available for many browsers.
We have written a blogpost about our experience implementing it.
FCM (firebase cloud messaging) can be implemented with Android, iOS and web(specified Google Chrome) only. So for using it on web application for all browser we have to implement the firebase database. You can see this implementation of firebase database
You can also use Firebase Cloud Messaging for web with Jquery like:
$("#button").click(function(){
var json = {
"to": "dBbB2BFT-VY:APA91bHrvgfXbZa-K5eg9vVdUkIsHbMCwHRVc8dBAvoH_3ZxxxxxVVeMXP7Bm0iera5s37ChHmAVh29P8aAVa8HF0I0goZKPYdGT6lNl4MXN0na7xbmvF25c4ZLl0JkCDm_saXb51Vrte",
"notification": {
"title": "Push enviado com JQuery",
"body": "Corpo de mensagem web!"
},
"data": {
"titulo": "Título da mensagem de dados!",
"descricao": "Corpo dos dados..."
}
};
$.ajax({
url: 'https://fcm.googleapis.com/fcm/send',
type: "POST",
processData : false,
beforeSend: function (xhr) {
xhr.setRequestHeader('Content-Type', 'application/json');
xhr.setRequestHeader('Authorization', 'key=AIzaSyBShxxxxXevRq0trDbA9mhnY_2jqMoeChA');
},
data: JSON.stringify(json),
success: function () {
console.log("Mensagem enviada com sucesso!");
},
error: function(error) {
console.log(error);
}
});
});
You can see it here: https://github.com/ShaheerDev/RealtimeWebChatApp
(I have used authentication to log the user in and realtime-database to get and send messages to database. It also updates in realtime)

Resources