I’m implementing Firebase Cloud Messaging (FCM) and am experiencing a problem that I’m unable to solve. I have implemented FirebaseMessagingService and FirebaseInstanceIdService according to the guide(s). When I go to Firebase Console for my app, and use the Notification function, I can successfully send a message to ALL my app instances (using the package name).
Now, in the code I have fetched the Firebase Instance Id (token) by use of the following code:
String token = FirebaseInstanceId.getInstance().getToken();
SendFirebaseTokenToServer(token);
(note that currently I’m using HTTP protocol, as my server does not yet have a cert). Anyway using the token I get from the call above, I go back to the Firebase Console and try to send a message to one (1) installed instance of my app. I grab the token from our server DB where it is stored as "varchar(max)". When I do that I get the following error message:
Invalid registration token. Check the token format.
I have googled that and found only one hit (having to do with Firebase and iOS):
http://stackoverflow.com/questions/41343520/ios-invalid-registration-token-check-the-token-format
That issue indicates that a cert was required (I think I’m reading it correctly). I’m not sure what I’m doing wrong. I need to get this to work using the Firebase Console first, then my server guy can start on his end knowing that it should work.
Turns out i was programatically encoding all POST or PUT parameters prior to sending to our server. the FCM token had a semicolon in it, which got encoded to a "%3A", seemingly causing the problem.
do NOT encode the FCM token.
Related
I try about week to send notification between devices using Firebase Functions now i found delay or the notification don't received to another device so after many trys i found solution is iam generate wrong token so i seek now the right way to generate tokens
FirebaseInstanceId.getInstance().getToken()
its return wrong token
extends FirebaseMessagingService
cant know how it works and after many tries it still return null
This is complicated but I'll try to be as concise as possible. I am using FCM to send push notifications to Android devices. My backend is parse server. I can successfully send pushes from the FCM console to the device. And when I send pushes from parse to https://mybackend/parse/push, it says {"result": "true" } as the response. I have checked the server logs, and it (predictably) says all http post requests to /parse/push were 200 success.
However when sending from parse (using curl or the parse push console), the pushes do NOT show up in FCM console. There is some issue between parse server and FCM then.
In my index.js, I have:
push: {
android: {
senderId: "XXXXX",
apiKey: "YYYYYY"
}
}
I have the keys, and done everything according to here: http://parseplatform.org/docs/parse-server/guide/#push-notifications
what else am I missing? Why can't I get this to actually appear on the device? Any help is greatly appreciated, thanks.
Setting up a Parse Server for an Android app, I remember having to double check this to get it right. The key for me was this: when I logged into Firebase console and selected the app I was working on, and clicked on the gear [or cog or whatever] and then Project Settings, I had to make sure to click on the Cloud Messaging tab and grab the Legacy server key [under project credentials] NOT the web api key that appears on the General tab. Also the sender ID that you want to use appears on that page.
I'm not sure when they will deprecate the Legacy server key, you might try the Server key instead, but definitely make sure you get the info off of the Cloud Messaging tab.
I don't know why FCM (and APNs) don't send a different message when the key (or cert) is not set up right [that would be more developer-friendly at least] and instead just send a 200 but my guess is that they evaluate the key [or cert] after receiving the intended notification and sending a response.
If I send push message by selecting a package from Firebase console, the push goes to all devices, but during sending to individual device, it displays the error:
Invalid reg token,please check token format
Error Snapshot:
UserID in console is not the registration token for Firebase messaging. By Firebase docs:
on initial startup of your app, the FCM SDK generates a registration token for the client app instance. If you want to target single devices or create device groups, you'll need to access this token by extending FirebaseInstanceIdService.
My last registration token looks like
cpeBAc1NkUE:APA91bEpAKHQTdgkWVdDzDZG8BPon0APaIhbbuSejDpZF-FO1gD2saDV7_EQDo2WEz0H6e5U-uf0i-v4b25NXgGzV2oUrNuboM5675WY7VCP3JcBl8BCNY7eV0VFGHT9oRox0EEoo_ch
In the other answer, you mentioned in the comments that you're Registration Token is:
cbuJIjkg9zQ%3AAPA91bHavuWCuRuWIBrDOoHUK-RsjU1yewigurrYzHe0cPiTQINykKjrLf8E0qEwJj3XmJ1IoTmn0r2EoLR_mAHGOjlA61CnQ8aSn2WxWKKByOwbsnqoVeaeWQIeGU_yh4wnZ67soLtI
I noticed the % (percentage character) included in it, which isn't a usual character included in registration tokens. Figured that it was possible that this was encoded somehow. When decoded, this is the value:
cbuJIjkg9zQ:APA91bHavuWCuRuWIBrDOoHUK-RsjU1yewigurrYzHe0cPiTQINykKjrLf8E0qEwJj3XmJ1IoTmn0r2EoLR_mAHGOjlA61CnQ8aSn2WxWKKByOwbsnqoVeaeWQIeGU_yh4wnZ67soLtI
Notice that the %3A was turned into : (colon). This is one of the usual characters. So I would suggest that you try the value above.
And as a reminder, the InvalidRegistration error (emphasis mine):
Check the format of the registration token you pass to the server. Make sure it matches the registration token the client app receives from registering with Firebase Notifications. Do not truncate or add additional characters.
Don't even encode it. Use it as is. Also, do note that the Registration Token should be kept secret.
I´m trying to use FCM to send Firebase Notifications, but I have a Application using one Firebase Project and a library using another Firebase Project. I want to receive the token from library Firebase Project to receive Firebase Notifications.
When I try directly receive the token using:
FirebaseInstanceId.getInstance().getToken();
I received a valid token, but from Application Firebase Project. If i try to force in getInstance() the library Firebase Project, using:
FirebaseInstanceId.getInstance(FirebaseApp.getInstance("ABC")).getToken();
I receive null. If I try to use Application or Library Firebase Project passing parameters in getToken() as:
FirebaseInstanceId.getInstance().getToken(getApplication().getResources().getString(R.string.gcm_defaultSenderId), FirebaseMessaging.INSTANCE_ID_SCOPE);
or
FirebaseInstanceId.getInstance(FirebaseApp.getInstance("ABC")).getToken(getApplication().getResources().getString(R.string.gcm_defaultSenderId), FirebaseMessaging.INSTANCE_ID_SCOPE);
I received the same valid token from Application Firebase Project.
the R.string.gcm_defaultSenderId is from library project resources
There is another way to receive Library Firebase Project token or I'm doing something wrong?
This is my understanding of what you are observing based on my experiments and the documentation.
When you first call getToken() using a FirebaseApp other then the default, there is no token and communication with the server is required to produce one. A null value is returned and the process to fetch a token is initiated. The documentation for getToken() says it returns "the master token or null if the token is not yet available". After a few seconds the token is received. You can detect that event using the onTokenRefresh() method of FirebaseInstanceIdService, if you have implemented that. On subsequent calls to getToken() for the non-default app, the token will be present and returned immediately by getToken().
I think the calls to get a scoped token always return a token because they are blocking (see docs), and wait for the interaction with the server to complete before returning a result.
I made a mistake in FirebaseApp.initializeApp(), because I forgot to set:
.setGcmSenderId(getApplication().getResources().getString(R.string.gcm_defaultSenderId))
in FirebaseOptions.Builder().
After that change, I receive a valid Library Firebase Token in getToken() and in onTokenRefresh()
I'm trying to authenticate a mobile application for the Android platform to a custom node.js server api. I would like to use Google OAuth2 tokens for this rather than roll my own authentication, since Android devices with Google Play installed make this available to app developers. I'm using the GoogleAuthUtil.getToken call from the Google Play Services library, documented here. I'm trying to follow the advice outlinedin this android developers blogpost
The getToken method is returning in my case a long 857 byte string. If I try to pass this token to Google's TokenInfo endpoint, it returns:
{'error': 'invalid_token', 'error_description': 'Invalid Value'}
What am I doing wrong here? In the 'scope' of the getToken call, I am sending:
audience:server:client_id:**i_put_my_clientid_here**. I have a clientid generated for "installed applications". Using this client id, the call to getToken doesn't work at all. When I generated a client id for a "service account", the call succeeds, but I get an 857 byte token that fails when passed to the TokenInfo endpoint as described above.
EDIT:
I also created a client id for "web applications", as it appears that is the right client id to use when calling getToken. But the behavior is the same, I get back an 857 byte token that doesn't validate when calling Google's endpoint.
How can I properly get a valid auth token using Google Play services on Android? Once I have the right token, what is the right node.js library to validate it server side? Can I use passport-google-oauth ?
Hm, this is really a comment rather than an answer, but I can’t put newlines in those:
it has to be the web-side Clent ID that goes in the put_my_clientid_here spot
if GoogleAuthUtil.getToken() gives you a String withou throwing an Exception, it really ought to be valid. When you hit tokeninfo, did you use ...tokeninfo?id_token=<857-byte-value-here>
if you’re a rubyist, grab the google-id-token gem and see if it can validate your 857-byte token.
If you just want to read the contents of the data returned by GoogleAuthUtil.getToken then the process is very simple. The returned data is simply a JWT. So all you'd have to do is split the data by the . character, and then base64 (url) decode each piece.
It gets slightly more complicated if you want you want to verify the message's authenticity. Simply use your favorite crypto library to do the verification. The 3rd component of the JWT is the signature of the data and the Google certs are publicly available; that's all you need to verify the message.
For a week I have been looking into how to validate GoogleAuthUtil tokens received in Android Client application at Node.js server using passport.js
Finally I came across passport-google-token passport strategy which perfectly performs the task.
https://www.npmjs.com/package/passport-google-token
More details are present in the above link.
The official node SDK lets you do that now.
Here's the link: https://github.com/google/google-auth-library-nodejs/blob/master/lib/auth/oauth2client.js#L384
I'm not too familiar with the details of how Android works with respect to handing a token from the device to the server. My general impression, however, is that you don't go through the typical web-based OAuth dance. Instead, you directly call the "user info" endpoint, which will return the info corresponding to the user who holds the token, or reject the request if the token is invalid. There's some discussion on this related question:
validating Android's authToken on third party server
In effect, the token becomes a secret that is shared between both the device and your server, so its important to protect it.
There are a couple strategies for Facebook and Twitter that were developed to do similar things using tokens from iOS devices:
https://github.com/drudge/passport-twitter-token
https://github.com/drudge/passport-facebook-token
You can take some inspiration from them and tweak it to talk to Google's endpoints. Let me know how this turns out. I'd love to see a similar "passport-google-token" strategy, so if you implement one, let me know and I'll link to it!