Firebase Messaging v1 401 Project Not Permitted error - javascript

I am running a node server with the firebase admin sdk. However, everytime I try to send a push notification from the server, I get a 401 error.
Here's the exact error I'm getting:
errorInfo: {
code: 'messaging/authentication-error',
message: '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. Raw server response: "<HTML>\n' +
'<HEAD>\n' +
'<TITLE>PROJECT_NOT_PERMITTED</TITLE>\n' +
'</HEAD>\n' +
'<BODY BGCOLOR="#FFFFFF" TEXT="#000000">\n' +
'<H1>PROJECT_NOT_PERMITTED</H1>\n' +
'<H2>Error 401</H2>\n' +
'</BODY>\n' +
'</HTML>\n' +
'". Status code: 401.'
},
codePrefix: 'messaging'
I'm not exactly sure why I don't have permissions to the project. I have setup my service account, and downloaded the .json file. I even went into the gcloud platform and tried to add any permission that looked correct. Below are all the permissions associated with my service account:
I am running the server locally, and initialized the app like this:
const admin = require('firebase-admin');
const messaging = require('firebase-admin/messaging');
const serviceAccount = require('<path-to-key>');
const fbApp = admin.initializeApp({
credential: admin.credential.cert(serviceAccount),
projectId: '<PROJECT_ID>',
databaseURL: '<DB_URL>'
});
I am not sure what else to do as I've looked through the v1 documentation multiple times and still don't have any clue as to what permissions I'm lacking. I even made sure to "firebase login" into the correct google account to see if that could've been an issue.
Here's my code to send a message:
const sendPushNotifications2 = async (topic, reminder) => {
const payload = genPayload2(reminder);
//await messaging.getMessaging(fbApp).sendToTopic(topic, payload);
await admin.messaging(fbApp).sendToTopic(topic, payload);
};
I have verified the client_id, client_email, and private_key_id values in the .json file. I haven't yet verified the private_key property because I'm not sure where to find it.

It turns out that I had this API disabled: "Firebase In-App Messaging API"
It also turns out that this question was asked before, but I wasn't able to find it. Here's the answer
If anyone else runs into this issue this was my fix:
go to the google cloud platform website
go to APIs and Services
go to Enabled APIs & Services
click + Enable APIs and Services
search for Firebase In-App Messaging API and make sure it's enabled.
You can also just search for messaging and make sure that all the cloud messaging APIs are enabled.

The problem is that new Firebase projects have only the new "Firebase Cloud Messaging API (V1)" enabled by default, and with that configuration - the official firebase-admin NodeJS library will not be able to send messages and will get 401 PROJECT_NOT_PERMITTED errors.
To be able to send message from your server, you MUST also enable the older "legacy" API.
From your Firebase console, go to Project Settings and open the Cloud Messaging tab.
Make sure that both APIs listed are enabled - see screenshot of how it should look:
If any API is not enabled, for the API that is disabled click the three dots menu on the right and select "Manage API"
In the Google Cloud Console page that opens, click the "Enable" button.
Note:
This is basically the same answer as #Tial's self answer, but I was confused by it and (as commented) it got some things wrong - it took me a while to understand it (and the linked answer) to get it right, so I had to clarify.

Related

firebase app check is not working with web client?

I have followed the official firebase app check installation tutorial:
https://firebase.google.com/docs/app-check/web/recaptcha-enterprise-provider
And I'm only getting errors.
I created and setup firebase project
Added app check library to my app
copy pasted app check initialization for web:
const appCheck = initializeAppCheck(firebaseApp, {
provider: new ReCaptchaEnterpriseProvider(
"my_recaptcha_key_here"
),
isTokenAutoRefreshEnabled: true, // Set to true to allow auto-refresh.
});
Enforced storage, enforced firestore from my console.
According to the tutorial, thats all you need to do.
RESULT:
Can't access anything from firestore, I get:
#firebase/app-check: FirebaseError: AppCheck: ReCAPTCHA error. (appCheck/recaptcha-error).
When uploading to storage, I get:
#firebase/app-check: FirebaseError: AppCheck: Fetch server returned an HTTP error status. HTTP status: 403. (appCheck/fetch-status-error).
Why is this happening, I have done all the steps in the tutorial?
Please make sure that the App URL is added to the reCAPTCHA allowed domains list.

How to submit the simple log with AWS CloudWatch Logs from frontend?

After about 1 hour of searching, I didn't find anything about 'how to submit a simple log to AWS CloudWatch Logs' from the frontend side. Almost all examples are for Node.js, but I need to submit the errors from the frontend, not form backend. I even did not found which package which I should use for the frontend.
To save, your time, I prepared the template of solution.
import { AWSCloudWatch } from "?????";
AWSCloudWatch.config({
// minimal config
});
if (__IS_DEVELOPMENT_BUILDING_MODE__ || __IS_TESTING_BUILDING_MODE__) {
console.error(errorMessage);
return;
}
if (__IS_PRODUCTION_BUILDING_MODE__) {
// Submit 'errorMessage' to AWS CloudWatch
// It would be something like
// AWSCloudWatch.submit(errorMessage)
}
You can use AWS SDK for JavaScript directly from your browser. Visit https://docs.aws.amazon.com/AWSJavaScriptSDK/latest/ for the guide.
Then you can call the putLogEvents method of AWS CloudWatchLogs API, assuming you already created log group and log stream. For guide visit https://docs.aws.amazon.com/AWSJavaScriptSDK/latest/AWS/CloudWatchLogs.html#putLogEvents-property
We're not supposed to be dumping browser-side error logs directly from the browser to CloudWatch. This presents an issue because posting logs to CloudWatch using SDK outside the AWS ecosystem requires API secret key and secret IDs, which means that it could be exposed to bad elements that could run MITM attacks and intercept our AWS credentials.
You will have two options to proceed with what you desire to do with less risk:
Use client-side libraries (Sentry) that were specifically designed to log errors and debugging information.
You can implement the sending of logs via an API that then forwards/proxies the logs towards CloudWatch.

Firebase authentication error: auth/invalid-credential

I've been experimenting with the authentication service provided by firebase for more than 2 weeks. Everything was perfectly working until yesterday it became impossible for me to use the facebook auth provider neither twitter to make users connect to my web app.
I've tried to sign out and sign in, I deleted my facebook and twitter apps and created others even with other accounts and the problem persists.
The same problem occurred when I tried to use the code they provide on their github which was working before.
The strange thing is that it's working fine when I use the google provider or the sign in with email and password method.
PS: I made sure the providers are enabled in the console.
const signInWithFacebookButton = document.getElementById('signInWithFacebook');
const auth = firebase.auth();
const signInWithFacebook = () => {
const facebookProvider = new firebase.auth.FacebookAuthProvider();
auth.signInWithPopup(facebookProvider)
.then(() => {
console.log('Successfully signed in');
})
.catch(error => {
console.error(error);
})
}
signInWithFacebookButton.addEventListener('click', signInWithFacebook);
Error message when I try to authenticate using facebook :
{code: "auth/invalid-credential", message: "The supplied auth credential is malformed or has expired."}
Error message when I try to authenticate using twitter:
{code: "auth/invalid-credential", message: "Error getting request token: 403 <?xml version="1.…ode-project-fd88e.firebaseapp.com/__/auth/handler"}
For Twitter login, the error code 403 indicates that access to the URL by the client is Forbidden. It gives such an error because you have to whitelist callback URLs(your site).
From documentation,
As part of our continued effort to ensure safety and security on the Twitter developer platform, any developer using Sign in with Twitter must explicitly declare their callback URLs in a whitelist in the Twitter apps settings which can be accessed in the apps dashboard when logged into your Twitter account on developer.twitter.com. This means that if the callback_url parameter used with the oauth/request_token endpoint isn't whitelisted, you will receive an error.
So in Twitter app settings, you have to add your URL say for example,
https://sitename.example.com/auth/twitter and https://sitename.example.com/auth/twitter/callback
You want to use https://yourdomain.com?source=twitter as your callback URL
Add this to the Twitter app dashboard: https://yourdomain.com
Use this in your call to oauth/request_token: https://yourdomain.com?source=twitter.
Refer this community article for more detail:-
Twitter callback URLs
This is worth as an answer: Always click to show your Facebook app secret before copying and pasting it into Firebase setting console. It is counter-intuitive, but Facebook did not implement the clipboard correctly so the hidden asterisk characters will just be copied and pasted verbatim.

Authenticating user in AWS Cognito User/Identity Pool with Google as identity provider

AWS provides two possible ways of dealing with Cognito:
"old one" via amazon-cognito-identity-js (and possibly amazon-cognito-auth-js) and
"new one" via aws-amplify (which inlcudes the above one)
After quite a bit of trouble and reverse engineering, I've successfully managed to sign in (receve back CognitoIdentityCredentials) using aws-amplify locally as part of the development effort.
The steps where (bear with me, as these are important for the questions to follow, and also might help someone):
Setup
Create a User Pool in Cognito console
Create a User Pool App Client in Cognito console
Create Google Web App in Google Console
Configure Google Web App to point to http://localhost:8080 (my local dev server)
Configure User Pool to use Google as an Identity Provider, supplying it with the Google Web App Client ID and Client secret from Google Console
Create an Identity Pool in Congnito console and configure it to work with Google as an Identity Provider, supplying Google Web App Client ID there as well
Implementation
Configure Amplify.Auth:
Amplify.configure({
Auth: {
identityPoolId: ,
region: ,
userPoolId: ,
userPoolWebClientId:
}
});
Inject Google API script:
const script = document.createElement('script');
script.src = 'https://apis.google.com/js/platform.js';
script.async = true;
script.onload = this.initGapi;
document.body.appendChild(script);
Init Google API:
window.gapi.load('auth2', function() {
window.gapi.auth2.init({
client_id: ,
scope: 'profile email openid'
});
});
Allow, on a button click, for a Google user to sing in:
const ga = window.gapi.auth2.getAuthInstance();
const googleUser = await ga.signIn();
const {id_token, expires_at} = googleUser.getAuthResponse();
const profile = googleUser.getBasicProfile();
User the profile, id_token, expires_at above to create a Cognito credentials session:
const user = {
email: profile.getEmail(),
name: profile.getName()
};
const credentials = await Auth.federatedSignIn(
'google',
{token: id_token, expires_at},
user
);
At this point a CognitoIdentityCredentials object was returned, properly populated, with token and all...
Problem
Unfortunately, aws-amplify adds a whopping 190K to my application webpack bundle (GZIPped, minified, optimized), which made me choke on my coffee.
Question 1
Can this somehow be reduced by a Babel plugin I'm missing (I'm guessing, no, since AWS is apparently still in 1995 and configures everything on a singleton Amplify and Auth objects).
Question 2
Have I made this unnecessarily complicated and there is a much more robust solution?
Question 3 (most important)
Can this be achieved using the "old way" amazon-cognito-identity-js, which is MUCH MUCH smaller?
I couldn't find, among all the (use cases)[https://github.com/aws/aws-amplify/tree/master/packages/amazon-cognito-identity-js/] a use case for social/federated login.
For me, the difference between
import Amplify from 'aws-amplify'
and
import Amplify from '#aws-amplify/core'
is ~500kB optimized and minified.
I think you also want
import Auth from '#aws-amplify/auth'
which adds only a little bit more.
But I agree, the aws-amplify package is really very large and it's not easy to figure out how to use the core components directly (e.g. aws-cognito-identity-js/es and aws-cognito-auth-js/es).
You could try using modularized exports in AWS amplify

Could not load the default credentials? (Node.js Google Compute Engine tutorial)

SITUATION:
I follow this tutorial: https://cloud.google.com/nodejs/tutorials/bookshelf-on-compute-engine
Everything works fine until I do npm start and go to:
http://localhost:8080
I am met with the following text on the blank page:
Could not load the default credentials. Browse to https://developers.google.com/accounts/docs/application-default-credentials for more information.
Which makes no sense since I am using OAuth. I followed the link and read the page, but I have no GOOGLE-APPLICATION-CREDENTIALS field anywhere, and nothing about it in the tutorial.
QUESTION:
Could you please reproduce the steps and tell me if you get the same result ?
(takes 5 minutes)
If not, what could I have done wrong ?
Yes, I had the same error. It's annoying cause Google Cloud Platform docs for their "getting started" bookshelf tutorial does not mention this anywhere. Which means that any new developer who tries this tutorial will see this error.
Read this:
https://developers.google.com/identity/protocols/application-default-credentials
I fixed this issue by running:
gcloud auth application-default login
In order to run thisgcloud auth application-default login
Visit: https://cloud.google.com/sdk/install
1) You have to install sdk into your computer
2) That will enable you to run the code
3) Log in to your associated gmail account then you are good to go!
This will make you login, and after that you code locally will use that authentication.
There are 2 solutions for this problem. One option, as mentioned by others, is to use gcloud auth application-default login
Second option is to set the environment variable GOOGLE_APPLICATION_CREDENTIALS. It should point to a file that defines the credentials. To get this file you need to follow these steps:
Go to the API Console Credentials page.
From the project drop-down, select your project.
On the Credentials page, select the Create credentials drop-down, then
select Service account key.
From the Service account drop-down, select an existing service account
or create a new one.
For Key type, select the JSON key option, then select Create. The file
automatically downloads to your computer.
Put the *.json file you just downloaded in a directory of your
choosing.
This directory must be private (you can't let anyone get access to
this), but accessible to your web server code.
Set the environment variable GOOGLE_APPLICATION_CREDENTIALS to the
path of the JSON file downloaded.
See https://developers.google.com/identity/protocols/application-default-credentials for details
Create a service account key using and download the json file. https://console.cloud.google.com/apis/credentials/serviceaccountkey
Add this to your ENV file
GOOGLE_APPLICATION_CREDENTIALS = "<PATH_TO_SERVICE_ACCOUNT_JSON_FILE>"
E.g:
GOOGLE_APPLICATION_CREDENTIALS=/Users/hello/Documents/ssh/my-10ebbbc8b3df.json
I was facing the same issue. It got fixed with following command.
gcloud auth application-default login
It stores default gcloud cloud credentials on your system and uses the same.
I got this error because of initially I did like below:
var admin = require("firebase-admin");
admin.initializeApp(); // I didnt add anything because firebaserc file include appName
It worked when I deployed the functions but not in serve. So this is how I solved it:
Go to the firebase Project settings(click on setting icon from side nav).
Click on the Service accounts.
Copy the admin sdk configuration snippet from selecting your pro. lang.
Ex (node.js):
var admin = require("firebase-admin");
var serviceAccount = require("path/to/serviceAccountKey.json");
admin.initializeApp({
credential: admin.credential.cert(serviceAccount),
databaseURL: "https://your-domain.firebaseio.com"
});
Now we need to add serviceAccountKey.json file.
Click on the Manage service account permissions in top right corner.
Now, you will see services accounts for your project, in the table find the row with column name name and value firebase-adminsdk, in that row click on Action dots and select Create key.
From the pop up dialog select Key type as json and press create button.
You will prompt to download the file, download it to your functions directory in project(You can customize this as you want and if you pushing to github, make sure to ignore that file).
Now, if you save it into the same directory where you are initializeApp(), access that file like: ./socialape-15456-68dfdc857c55.json(In my case, both files are located: functions/index.js and functions/services.son in functions directory and in index.js file, I initialed my firebase admin sdk).
Ex(node.js):
const functions = require('firebase-functions');
var admin = require("firebase-admin");
var serviceAccount = require("./myapp-15456-68dfdc857c55.json");
admin.initializeApp({
credential: admin.credential.cert(serviceAccount),
databaseURL: "https://myapp-15456.firebaseio.com"
});
It's a best and good idea to create .env file and include your file there and access it as others mentioned. I leave that part to you.
Hope this help someone on the planet. Regards!
If you're running the app locally, then the gcloud beta auth application-default login command should suffice for acquiring local credentials (I updated the tutorial to say so).
When running the app on Google Compute Engine, if the Compute Engine instance was created with the proper scopes (cloud-platform should be sufficient) then the app will authenticate with Google Cloud Platform APIs automatically without any extra work on your part.
Go here: https://firebase.google.com/docs/admin/setup#initialize_the_sdk and follow the instructions to create a private key.
Then after you have downloaded your private key open command prompt in the project directory and do the following command:
set GOOGLE_APPLICATION_CREDENTIALS=C:\YOUR-PATH\YOUR-KEY.json
use this to solve your issue. this actually works:-
just put credential parameter and give reference to your key to it.
const serviceAccount = require('../key.json');
admin.initializeApp({
credential: admin.credential.cert(serviceAccount)
});
Another solution i found: in your package.json add an export command like this:
"scripts": {
"start": "export GOOGLE_APPLICATION_CREDENTIALS='./gcloud.json' && node ./bin/www --exec babel-node --presets babel-preset-env",
},
You have to create an object of your SessionsClient.
Here I will provide some steps, so you can run your code like a charm.
You have to go into your Dialogflow dashboard.
Click on setting ( Left navbar top-right gear icon)
in the General tab click Service Account link ( it will redirect you to another screen)
If you have a service account then ignore step 5
Create a service account ( Top-center +icon button)
Now you have a service account on a list click on
From the action, field presses the 3 vertical dots and create a key.
Download the JSON file on your local computer.
Assign object to your sessionClient.
const sessionClient = new dialogflow.SessionsClient({
keyFilename: "/var/www/html/moqatrips/dialog-flow.json"
});
For all people using firebase, what it worked for me was passing the credentials to the KeyManagementServiceClient constructor
const serviceAccount = require('../keys/file.json'); //<- your firebase credentials
const client = new KeyManagementServiceClient({
credentials: serviceAccount,
});
I also had this error problem, here I had not created the object of
keyFilename (stores the credentials of the api)
in the sessionClient object for nodejs app.
const sessionClient = new dialogflow.SessionsClient({
keyFilename: "./keyCredentials.json"
});
const sessionPath = sessionClient.sessionPath(projectId, sessionId);
To download 'keyCredentials.json' goto:
https://console.cloud.google.com/apis/credentials/serviceaccountkey
Also add the path of this file to the system variables
In windows open powershell
type GOOGLE_APPLICATION_CREDENTIALS = [PATH_TO_SERVICE_ACCOUNT_JSON_FILE]
you may find youself in another part of the world -- and land here. I'm adding to a three year old question because its keywords matched my issue and the preceding answers helped me although none describe my issue
firebase deploy --only functions --debug
produced
[2020-12-02T08:31:50.397Z] FirebaseError: HTTP Error: 429, Unknown Error
Error: Could not read source directory. Remove links and shortcuts and try again.
I could not find anything wrong with the source directory. But that was all so many tiny fish.
Examining the error in detail, from the top, lead to:
Our systems have detected unusual traffic from your computer network. This page checks to see if it's really you sending the requests, and not a robot.
The block will expire shortly after those requests stop.
Out of curiosity and exhaustion, I waited first. The wait reset duration is > than 30 minutes. So i pursued the captcha to prove my enduring humanity which did register eventually after some oauth warnings.
Although this question has been answered multiple times, I found myself in a situation not explained here.
After I created the variable: $GOOGLE_APPLICATION_CREDENTIALS, I was getting the same error as Coder1000.
However, I was running both: nodemon and: npm run dev in two separate sessions in Terminal, neither of which were aware of the variable.
Once I: shut the tabs down; added new tabs; and ran the commands again, the application was able to access the variable.
download Cloud SDK installer from this site. https://cloud.google.com/sdk/docs/install
run this command -> gcloud auth application-default login
If anyone ran into the issue just like me and doesn't want to set the variable each time before running their code it's best to manually set the environment variable. Name it GOOGLE_APPLICATION_CREDENTIALS and browse the downloaded JSON file. If you don't know the steps follow this: https://docs.oracle.com/en/database/oracle/machine-learning/oml4r/1.5.1/oread/creating-and-modifying-environment-variables-on-windows.html#GUID-DD6F9982-60D5-48F6-8270-A27EC53807D0

Categories