I'm new to Firebase Cloud Messaging and I need to implement notifications in my webapp.
If the browser requests notification for the first time there is no error occurred and the token fetched successfuly. But if I delete the notification from the browser parametre (I use Chrome) and ask for permission again, it shows me an error in the console.
DELETE https://fcmregistrations.googleapis.com/v1/projects/teak-perigee-*****/registrations/dcVW8MdcapIy5CrSqGutkj:APA91bFoslZEsjgIk16CUfol*****************
FirebaseError: Messaging: A problem occured while unsubscribing the user from FCM: FirebaseError: Messaging: A problem occured while unsubscribing the user from FCM: Internal error encountered. (messaging/token-unsubscribe-failed). (messaging/token-unsubscribe-failed).
Actually the token is fetched even this error occurs. but in this situation I handle the new token in the catch block of the promise. This is my code when permission is fired:
askForPermissioToReceiveNotifications = () => {
const messaging = firebase.messaging();
Notification.requestPermission().then(async (permission) => {
if (permission == 'granted') {
try {
const token = await messaging.getToken();
if (token) {
console.log(token);
return token;
} else {
console.log('No Instance ID token available. Request permission to generate one.');
}
} catch (error) {
console.log('An error occurred while retrieving token. ', error);
//BUT THE NEW TOKEN SUCCESSFULY FETCHED
const token = await messaging.getToken();
if (token) {
console.log(token);
return token;
} else {
console.log('No Instance ID token available. Request permission to generate one.');
}
}
}
})
.catch(error => console.log(error));
}
I don't know if I miss something and I hope I can find a solution.
I faced a similar issue and believe this may be the explanation.
Issue was introduced in version 7.0.0 of the firebase-js-sdk. A workaround for now is to use version 6.6.2 or lower. I have filed a Github issue here for users effected to track.
So to enable use an older version just update the following in your index.html:
<script src="/__/firebase/6.6.2/firebase-app.js"></script>
<script src="/__/firebase/6.6.2/firebase-messaging.js"></script>
and change the following to your service worker file (typically named: firebase-messaging-sw.js):
importScripts('/__/firebase/6.6.2/firebase-app.js');
importScripts('/__/firebase/6.6.2/firebase-messaging.js');
it turns out that new versions of Firebase SDKs depend on a new internal infrastructure service, called FIS (the Firebase Installations Service) for targeting identifiers ("FIDs" or "Instance-IDs").
If you are using API key restrictions for the API keys you use in your application, you will have to extend those restrictions to allow usage with the new Firebase Installations Service at firebaseinstallations.googleapis.com.
To allow your API key in question to be used with the new Firebase Installations API:
go to the Google Cloud Console
choose the relevant project (i.e. the project you use for your application)
open the menu and go to APIs & Services -> Credentials
click Edit API key for the API key in question
scroll down to API restrictions
from the dropdown, choose FCM Registration API
click Save
wait a couple of minutes for Google servers to update and retry...
The Firebase library has a bug where it saves the token in an indexed database in your app. When you delete your credentials, it fails to delete the token and instead tries to fetch the old token when creating a new one, which leads to an error since the token no longer exists in Firebase. To resolve the issue, simply follow these steps.
-Open Google Chrome DevTools by pressing F12
-Click on the Application tab.
-Expand the Storage section in the left-side panel.
-Expand IndexedDB
-Expand firebase-messaging-database
-Right click on the key-value and delete it
-Refresh your app and the error is gone
Related
I'm implementing Google Cloud's service-to-service authentication documentation between two apps hosted on Cloud Run. A client-side React app - created using create-react-app - will be making calls to a server-side Node.js app, where the latter doesn't have unauthenticated invocation allowed.
However, I'm not able to query the internal metadata server form my React app to get an authorization token. When running the request in the sample code on that page, I get the error in the attached screenshot. Does anyone have a solution to this?
Code to make call:
const buttonClickHandler = async (event) => {
const metadataServerTokenURL = 'http://metadata/computeMetadata/v1/instance/service-accounts/default/identity?audience=';
const tokenRequestOptions = {
uri: metadataServerTokenURL + process.env.REACT_APP_API_BASE_URL,
headers: {
'Metadata-Flavor': 'Google'
}
};
// Fetch the token, then provide the token in the request to the receiving service
request(tokenRequestOptions)
.then((token) => {
return request(process.env.REACT_APP_API_BASE_URL).auth(null, null, true, token)
})
.then((response) => {
console.log(response)
})
.catch((error) => {
console.error(error)
});
}
Error:
TypeError: Failed to fetch
Browser console error
This service-to-service procedure you linked in your question is, as mentioned in the name, for service to service communication.
The documentation you shared mentions this:
Note that this method does not work outside of Google Cloud, including from your local machine.
The metadata server is not intended to be called from outside Google Cloud. This is why it is not working in your browser.
If you are calling a backend container, you could:
make this backend container callable by unauthenticated users (IAM role: "roles/run.invoker", member: "allUsers")
Implement token retrieval with firebase/auth and the Identity Platform.
Error encountered
This operation is not supported in the environment this application is running on. "location.protocol" must be http, https or chrome-extension and web storage must be enabled.
I am trying to use signin with email link in firebase and React Apllication build using EXPO
when i run this code i get the email link but when i click on that link i get this error
My code is
const actionCodeSettings = {
url: ` https://servy-a8ef2.firebaseapp.com`,
handleCodeInApp: true,
};
await firebase
.auth()
.sendSignInLinkToEmail(email, actionCodeSettings)
.then(function () {
})
.catch(function (error) {
console.log("error", error);
// Some error occurred, you can inspect the code: error.code
});
I don’t know if it’s still relevant, I had the same error. Maybe for someone it will be useful.
First of all, check your link, there is a space before https, firebase may encode it as "%20https..." That’s why it does not work. And check your quotes as well, the back quotes can be encoded differently.
I had problem with an environmental variable, i put the value with quotes, that google encoded as "%27http......%27". So that was my error.
Quick Background: I'm programming an API that is thought to be used "standalone" i.e. there is no frontend involved. API access should be possible directly from e.g. Postman or Curl with a Bearer token in the Authentication Header.
I was looking at Google Firebase and thought it is probably a really good fit because all of the authentication is already "builtin" and directly compatible with Google Cloud Functions.
However after a weekend of experimenting I can not seem to figure out how to implement an REST API (With Google Cloud Functions) where the User can (In an web-interface) request an API token to interact with the API.
I don't want to handle authentication myself. I really would love to use the Firebase authentication for the API.
Here is what the final process should look like:
User logs into an web-interface with the standard Firebase Authentication process.
User clicks on something like "Request API Key" and gets a key shown in the web-interface (e.g. abc...). that is generated by Firebase Authentication.
User can make requests with e.g. curl to the API Hosted in Google Cloud Functions and just has to set the Authorization Header (Bearer abc...) and the "validation" of that token is handled by Firebase Authentication.
Here is what I already tried to generate the token:
admin.auth().createCustomToken(uid)
.then(function(customToken) {
console.log(customToken);
})
.catch(function(error) {
console.log('Error creating custom token:', error);
})
And then set the Token logged to the console in Postman as Bearer Token, and then use the following function to verify the token:
const authenticate = async (req, res, next) => {
if (!req.headers.authorization || !req.headers.authorization.startsWith('Bearer ')) {
res.status(403).send('Unauthorized');
return;
}
const idToken = req.headers.authorization.split('Bearer ')[1];
try {
const decodedIdToken = await admin.auth().verifyIdToken(idToken);
req.user = decodedIdToken;
next();
return;
} catch(e) {
console.log(e);
res.status(403).send('Unauthorized');
return;
}
}
Then I get this error
message: 'verifyIdToken() expects an ID token, but was given a custom token. See https://firebase.google.com/docs/auth/admin/verify-id-tokens for details on how to retrieve an ID token.'
I understand that if I would implement an web-interface I could grab the ID token from the devtools (?), but the token is then only valid 1 hour... What I need is a token that is valid "indefinitely" and can be generated and shown to the user.
I think I know that I have to use Custom Tokens somehow but can not figure out how to get them working... (https://firebase.google.com/docs/auth/admin/create-custom-tokens).
Thanks very much in advance everybody!
Best
Rick
You're trying to build an API management solution on top of Firebase and Cloud Functions. Custom tokens and ID tokens are not suitable for this purpose. Custom tokens are only meant to be used as a user authentication credential on end user devices, and ID tokens represent a successful auth response. Both types of tokens expire after an hour.
If you need long-lived, managed API keys, then you will have to implement them yourself. There's nothing built into Firebase that you can use out of the box. I once implemented such a solution as a prototype, where I generated a Firestore document each time a user signed in and requested an API key. Then I used the document ID as the API key, which I could validate in the Cloud Function.
const apiKey = req.headers.authorization.split('Bearer ')[1];
const doc = await admin.firestore().collection('apiKeys').doc(apiKey).get();
if (doc.exists) {
next();
}
I also had to implement some local API key caching to make this work efficiently.
You might be able to avoid some of this work by using a solution like Google Cloud Endpoints (https://cloud.google.com/endpoints), although I don't have any personal experience with that. Finally, also look at open source solutions like https://wso2.com/api-management/ that enable you to set up your own API key management and gateway.
I am trying to get the token of my current device via firebase cloud messaging. I am using the following code:
messaging.getToken().then(function(refreshedToken) {
console.log("success ",refreshedToken);
}).catch(function(err) {
console.log('Unable to retrieve refreshed token ', err);
});
I then registered the device as part of a device group for one of my users(as per the firebase documentation). Now, however, whenever I try to get my device token, I get the following error: "The operation failed because the stored database is a higher version than the version requested." I tried clearing local history, but that didn't help. I also tried switching browsers. I don't know what the "stored database" even is. Is there any way to fix this? thanks!
I'm using anonymous authentication is a Firebase app. I just noticed that I have over 100 anonymous users now registered even though all I've been doing is testing the app. It looks like the expiration time for the user token is quite short, and as soon as it expires the next login causes a new user to be created.
What is the best way to avoid this? I could presumably refresh the user's token but I'm not sure how to this since in onAuthStateChange the user parameter is null if the user has expired.
Or should I changed the expiration time? If so, how do I do this? I found some instructions for doing so in the old Firebase docs but can't see how to do it in the latest version.
UPDATE: Currently I am initializing the app and authenticating the (anonymous) user like so:
firebase.initializeApp(FIREBASE_CONFIG);
firebase.auth().onAuthStateChanged(user => {
if (!user) {
firebase.auth().signInAnonymously().catch(error => {
console.error('Failed to authenticate with Firebase', error);
});
}
});