Firebase cloud messaging api v1 Expected OAuth 2 access token - firebase

I guess firebase disabled legacy api for new users. They want us to use v1 api.
When i try to send notification with postman i get this .
"error": {
"code": 401,
"message": "Request had invalid authentication credentials. Expected OAuth 2 access token, login cookie or other valid authentication credential. See https://developers.google.com/identity/sign-in/web/devconsole-project.",
"status": "UNAUTHENTICATED"
}
I have service accounts, server key etc. But i dont now how to migrate .
I'm using dart-shelf backend and flutter.
For postman this is my configuration.
Authorization = Bearer +AAAAA..token
This is the body that i sent
{
"message":{
"token":"<generated token by flutter>",
"notification":{
"body":"This is an FCM notification message!",
"title":"FCM Message"
}
}
}
And this is how i generate token for specific device on flutter.
#override
void initState() {
super.initState();
WidgetsBinding.instance.addPostFrameCallback((timeStamp) async {
_init();
});
var initializationSettingsAndroid =
const AndroidInitializationSettings('ic_launcher');
var initialzationSettingsAndroid =
const AndroidInitializationSettings('#mipmap/ic_launcher');
var initializationSettings =
InitializationSettings(android: initialzationSettingsAndroid);
flutterLocalNotificationsPlugin.initialize(initializationSettings);
FirebaseMessaging.onMessage.listen((RemoteMessage message) {
RemoteNotification? notification = message.notification;
AndroidNotification? android = message.notification?.android;
if (notification != null && android != null) {
flutterLocalNotificationsPlugin.show(
notification.hashCode,
notification.title,
notification.body,
NotificationDetails(
android: AndroidNotificationDetails(
channel.id,
channel.name,
color: Colors.blue,
// TODO add a proper drawable resource to android, for now using
// one that already exists in example app.
icon: "#mipmap/ic_launcher",
),
));
}
});
FirebaseMessaging.onMessageOpenedApp.listen((RemoteMessage message) {
RemoteNotification? notification = message.notification;
AndroidNotification? android = message.notification?.android;
if (notification != null && android != null) {
showDialog(
context: context,
builder: (_) {
return AlertDialog(
title: Text(notification.title!),
content: SingleChildScrollView(
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [Text(notification.body!)],
),
),
);
});
}
});
getToken();
}
My backend on google cloud computing.

I found solution for my problem. I will leave here solution for who needs it.
Your headers and body of your post is correct. You should exchange your authorization code for tokens.
Here is how you can test
1 - Open OAuth 2.0 Playground https://developers.google.com/oauthplayground/
2- Input your scope which is https://www.googleapis.com/auth/firebase.messaging (After you submit your scope it is gonna authorize to your google account)
3- Enter your authorization code (device's token which is given by firebase when u did your configuration for your UI) and click "Exchange authorization code for token"
Playground will give you access token and refresh token. You should put your access token like Bearer ya29... .
After you able to send notification with postman. But for your software you should automate exchanging tokens in your code.
Check out this repo for your programming language .
https://github.com/googleapis?q=auth

Related

How to stack fcm push notification and display it when internet gets on , Flutter firebase

I am using fcm for push notification , and i am trying to stack the notifications when the internet is off ,
What is happening now is
When the app doesn't have internet and the app if receives more than one notification , when the interent is switched on , only the latest notification is shown.
What I want to achieve is
When the app doesn't have internet and the app if receives more than one notification , when the interent is switched on , I want to show all the notifications not just the latest one.
I am presently using the following code snippets.
// Background and also terminated
FirebaseMessaging.instance.getInitialMessage().then((value) =>
Navigator.push(
context, MaterialPageRoute(builder: (context) => DummyScreen())));
// Background not terminated
FirebaseMessaging.onMessageOpenedApp.listen((RemoteMessage message) {
print(
"The message from within the onMessageOpenedApp and i am within the home_page is : " +
message.notification!.title.toString());
Navigator.push(
context, MaterialPageRoute(builder: (context) => DummyScreen()));
});
// When app is in foreground
FirebaseMessaging.onMessage.listen((RemoteMessage message) {
RemoteNotification? notification = message.notification;
AndroidNotification? android = message.notification?.android;
if (notification != null && android != null && !kIsWeb) {
flutterLocalNotificationsPlugin.show(
notification.hashCode,
notification.title,
notification.body,
NotificationDetails(
android: AndroidNotificationDetails(
channel.id,
channel.name,
// TODO add a proper drawable resource to android, for now using
// one that already exists in example app.
icon: 'launch_background',
),
),
);
}
});

Firebase Cloud Messaging click_action not working

I am sending notification from Firebase console to web application (Firebase). When I am sending a POST request from POSTMAN, I am able to navigate to the URL when I click on the notification. But when I am sending it from Firebase console I am not able to open the URL. Also, I need to add my logo as my Icon to the notification.
POSTMAN
{
"notification": {
"title": "Push notification test",
"body": "It works! 🎉",
"icon": "https://soft-ing.info/img/firebase.png",
"click_action": "https://google.com"
},
"to": "dLXCbmVCh5Y:APA91bGmFN7BUsKqwWFokyoBsoph6k4EhBQEflwJLFrPaUzTceYhAPYfFf8LqTRBVJGCA0gWS_0k0DUCeJBa7jdopIyjFQNprtp3lkQgLmUNRUibLIIMxAuBZeXuHTqaU-BA4QwbekN6"
}
Service Worker File Code
messaging.setBackgroundMessageHandler(function(payload) {
console.log('[firebase-messaging-sw.js] Received background message ', payload);
// Customize notification here
const notificationTitle = payload.data.title;//'Background Message Title';
const notificationOptions = {
body: payload.data.body,//'Background Message body.',
icon: payload.data.icon,
image : payload.data.image,
data:{
time: new Date(Date.now()).toString(),
click_action : payload.data.click_action
}
};
return self.registration.showNotification(notificationTitle,notificationOptions);
});
self.addEventListener("notificationclick", (event) => {
event.waitUntil(async function () {
const allClients = await clients.matchAll({
includeUncontrolled: true
});
let chatClient;
let appUrl = 'https://www.google.com';
for (const client of allClients) {
//here appUrl is the application url, we are checking it application tab is open
if(client['url'].indexOf(appUrl) >= 0)
{
client.focus();
chatClient = client;
break;
}
}
if (!chatClient) {
chatClient = await clients.openWindow(appUrl);
}
}());
});
There's some discrepancy in the above two snippets you shared.
In your case body: payload.data.body should be body: payload.notification.body, you need to do similarly for other places in service worker since that's how you are sending the request.

linking anonymous Firebase user with custom token user

I want users to be automatically logged in anonymously when they first visit the site, and then at any point they should be able to log in with an external provider such as Google or LinkedIn, and continue to use the data that had been stored under the anonymous account.
let currentUser = auth.currentUser;
if (!currentUser) {
currentUser = (await auth.signInAnonymously()).user;
}
I have implemented OAuth 2.0 flows to enable users to log into my system using various providers including LinkedIn. My back-end generates a JWT access token which is provided to the web client.
const accessToken = {
sub: my-service-account#my-firebase-project.iam.gserviceaccount.com,
iss: my-service-account#my-firebase-project.iam.gserviceaccount.com,
aud: "https://identitytoolkit.googleapis.com/google.identity.identitytoolkit.v1.IdentityToolkit",
uid: 1234
// other claims...
}
const newUser = await auth.signInWithCustomToken(accessToken);
All good so far - but how do I link the two? According to the account linking documentation I should be able to do something like this:
if (currentUser && currentUser.isAnonymous) {
const provider = new firebase.auth.OAuthProvider('myprovider');
const credential = provider.credential(token, token);
const linkedUser = await currentUser.linkWithCredential(credential);
}
However, firebase sends a request to https://www.googleapis.com/identitytoolkit/v3/relyingparty/verifyAssertion
{
idToken: {
"provider_id": "anonymous",
"iss": "https://securetoken.google.com/my-firebase-project",
"aud": "my-firebase-project",
"user_id": anonymousUserId,
"sub": anonymousUserId,
"firebase": {
"identities": {},
"sign_in_provider": "anonymous"
}
}
postBody: {
id_token: token,
access_token: token
providerId: "myprovider"
}
requestUri: "http://localhost"
returnIdpCredential: true
returnSecureToken: true
}
and I get a 400 error response:
INVALID_CREDENTIAL_OR_PROVIDER_ID : Invalid IdP response/credential: http://localhost?id_token=${token}&access_token=${token}&provider=myprovider
My front-end is https running on port 3000, and my backend is at /api/oauth/, also https
how do you configure a different requestUri?
what is the endpoint supposed to do?

Send push notifications using Firebase and OneSignal

Not sure if this is possible, but I have an existing Ionic 3 app which uses Firebase as a backend. Maybe it's just me, I'm not able to integrate Google login, Facebook login and push notifications in the same app. Been trying for a few days now.
I was able to install OneSignal and send push notifications to an Android device, but I want to send them programatically using tokens which are saved for each device, not from the OneSignal dashboard.
This is what I use in Firebase Cloud Functions to send notifications. Can it be modified to send the notification to OneSignal and then to each device?
`function sendFcm(userID, eventSnapshot, eventID) {
const getDeviceTokensPromise = admin.database().ref(`/fcmTokens/${userID}/`).once('value');
return Promise.all([getDeviceTokensPromise]).then(result => {
const tokensSnapshot = result[0];
const payload = {
"notification": {
"title": "Your invitation has arrived",
"body": eventSnapshot.name,
"sound": "default",
// "click_action": "FCM_PLUGIN_ACTIVITY",
"icon": "fcm_push_icon"
},
"data": {
"eventId": eventID,
"uid": userID,
"eventObj": JSON.stringify(eventSnapshot),
"notificationType": "newEventNotification"
}
};
const tokens = Object.keys(tokensSnapshot.val());
console.log(tokens);
// Send notifications to all tokens.
return admin.messaging().sendToDevice(tokens, payload).then(response => {
// For each message check if there was an error.
const tokensToRemove = [];
response.results.forEach((result, index) => {
console.log(tokens[index]);
const error = result.error;
if (error) {
console.error('Failure sending notification to', tokens[index], error);
// Cleanup the tokens which are not registered anymore.
if (error.code === 'messaging/invalid-registration-token' ||
error.code === 'messaging/registration-token-not-registered') {
tokensToRemove.push(tokensSnapshot.ref.child(tokens[index]).remove());
}
}
});
return Promise.all(tokensToRemove);
});
})
}`
After searching a bit, I found the OneSignal API. Seems that I just need to save the player id and send it or mutiple in an array to onesignal.com/api/v1/notifications. More details here: https://documentation.onesignal.com/reference#section-send-based-on-onesignal-playerids-create-notification

Expo, Firebase, Login with google

in my React Native Expo application, I want to authenticate the user with google account. so I followed the Expo Googlefor a normal sign in with google first, Which was working, then using the idToken and accessToken to authenticate with firebase.
signInWithGoogleAsync = async () => {
try {
const result = await Google.logInAsync({androidClientId: ***, iosClientId: ***, scopes: ["profile", "email"] });
if (result.type === "success") { // I get result object
const credential = firebase.auth.GoogleAuthProvider.credential( result.idToken, result.accessToken);
/* credential is and xf {} object */
firebase.auth().signInWithCredential(credential)
.then(user => {console.log( user);})
.catch(error => {console.log(error);});
return result.accessToken;
}
return { cancelled: true };
} catch (e) {
return { error: true };
}
};
but I get the following error:
[Error: {"error":{"errors":[{"domain":"global","reason":"invalid","message":"Invalid Idp Response: the Google id_token is not allowed to be used with this application. Its audience (OAuth 2.0 client ID) is 268165840544-097g31a3qhd0mm.apps.googleusercontent.com, which is not authorized to be used in the project with project_number: 747269174."}],"code":400,"message":"Invalid Idp Response: the Google id_token is not allowed to be used with this application. Its audience (OAuth 2.0 client ID) is 26816581eun236bp9vdb7b6r.apps.googleusercontent.com, which is not authorized to be used in the project with project_number: 747269174."}}]
Add url in error message => eg. your case = 268165840544-097g31a3qhd0mm.apps.googleusercontent.com
under
Authentication > Sign-in Method > Google
Whitelist client IDs from external projects (optional) on Firebase

Resources