I am new to Firebase and I am running into errors such as mismatch sender id and Authentication Error with HTTP status 401 when my Java application tries to send a notification/message using the client's Firebase token. Note that using Firebase Console, I am able to send the message to the client.
For the client app, I did the following:
messaging
quickstart app from here -- https://github.com/firebase/quickstart-android/tree/master/messaging -- which is already setup with Firebase dependencies and such. Loaded the cloned app in Android Studio
.My Notification Client
and added an app using com.google.firebase.quickstart.fcm
as the package name of the Android app.google-services.json
file for the Android app added to the newly created project and copied it to the messaging/app/
folder and sync'd with Grade files from within Android Studio
.Android Studio
. When the app got loaded in the emulator, clicked the Log Token
button to capture the client's Firebase token in the Android Monitor
tab in Android Studio
.My Notification Client
, clicked the Notifications
link from the left pane, and sent a notification to the device by pasting the Firebase token captured in the previous step.This worked great! The next step was to to use a separate simple Java application (which would eventually become a notification server) to send the notification to the client instead of using Firebase Console.
To accomplish this, I followed the steps outlined here -- https://firebase.google.com/docs/server/setup#prerequisites. Specifically, these are the steps that I performed:
My Notification Server
in Firebase Console.Settings > Permissions
in Firebase Console, created a new service account and downloaded the serviceAccountCredentials.json
file. <dependency>
<groupId>com.google.gcm</groupId>
<artifactId>gcm-server</artifactId>
<version>1.0.0</version>
</dependency>
<dependency>
<groupId>com.googlecode.json-simple</groupId>
<artifactId>json-simple</artifactId>
<version>1.1.1</version>
</dependency>
<dependency>
<groupId>com.google.firebase</groupId>
<artifactId>firebase-server-sdk</artifactId>
<version>3.0.0</version>
</dependency>
Then, I extended com.google.android.gcm.sender.Sender
to create FCMSender
and override protected method getConnection(String url)
to use the new FCM endpoint as shown below:
class FCMSender extends Sender {
public FCMSender(String key) {
super(key);
}
@Override
protected HttpURLConnection getConnection(String url) throws IOException {
String fcmUrl = "https://fcm.googleapis.com/fcm/send";
return (HttpURLConnection) new URL(fcmUrl).openConnection();
}
}
The main()
method of my Java application looks like this:
public static void main(String[] args) {
// Obtain serverKey from Project Settings -> Cloud Messaging tab
// for "My Notification Client" project in Firebase Console.
String serverKey = <get_server_key_from_firebase_console>;
Thread t = new Thread() {
public void run(){
try {
Sender sender = new FCMSender(serverKey);
Message message = new Message.Builder()
.collapseKey("message")
.timeToLive(3)
.delayWhileIdle(true)
.addData("message", "Notification from Java application");
.build();
// Use the same token(or registration id) that was earlier
// used to send the message to the client directly from
// Firebase Console's Notification tab.
Result result = sender.send(message,
"APA91bFfIFjSCcSiJ111rbmkpnMkZY-Ej4RCpdBZFZN_mYgfHwFlx-M1UXS5FqDBcN8x1efrS2md8L9K_E9N21qB-PIHUqQwmF4p7Y3U-86nCGH7KNkZNjjz_P_qjcTR0TOrwXMh33vp",
1);
System.out.println("Result: " + result.toString());
} catch (Exception e) {
e.printStackTrace();
}
};
t.start;
try {
t.join();
}
catch (InterruptedException iex) {
iex.printStackTrace();
}
}
When I run the Java application, I get MismatchSenderId
error. I tried troubleshooting using curl
as shown below but got the same error:
$ skey=<obtained_from_project_settings_cloud_messaging_tab_in_firebase_console>
$ curl -X POST --header "Authorization: key=$skey" \
--Header "Content-Type: application/json" \
https://fcm.googleapis.com/fcm/send \
-d "{\"to\":\"APA91bFfIFjSCcSiJ111rbmkpnMkZY-Ej4RCpdBZFZN_mYgfHwFlx-M1UXS5FqDBcN8x1efrS2md8L9K_E9N21qB-PIHUqQwmF4p7Y3U-86nCGH7KNkZNjjz_P_qjcTR0TOrwXMh33vp\",\"data\":{\"message\":\"Yellow\"}}"
{"multicast_id":7391851081942579857,"success":0,"failure":1,"canonical_ids":0,"results":[{"error":"MismatchSenderId"}]}
Instead of using the Server Key
listed on Project Settings > Cloud Messaging
tab for My Notification Server
project in Firebase Console, I tried using the Project Number
but that caused InvalidRequestException: HTTP Status Code: 401
.
Firebase documentation of the error codes says this about MismatchSenderId
:
Mismatched Sender 200 +
error:MismatchSenderId
A registration token is tied to a certain group of senders. When a client app registers for FCM, it must specify which senders are allowed to send messages. You should use one of those sender IDs when sending messages to the client app. If you switch to a different sender, the existing registration tokens won't work.
I could not figure out where/how in Firebase Console one can configure the Android app(which was aded to the My Notification Client
project) to be able to receive messages.
Any help on this, would be appreciated!
I too have recently started using Firebase, with no prior experience in Google Cloud Messaging. AFAIK, there's no server side SDK for Firebase Cloud Messaging, currently.
To send notifications/messages from your App Server to your Mobile Client, you need to implement your own HTTP and/or XMPP methods. See https://firebase.google.com/docs/cloud-messaging/
My testing code, using HTTP:
public CompletableFuture<String> fcmTest1() {
// https://firebase.google.com/docs/cloud-messaging/http-server-ref
String host = "fcm.googleapis.com";
String requestURI = "/fcm/send";
String CLIENT_TOKEN = "ASK_YOUR_MOBILE_CLIENT_DEV"; // https://developers.google.com/instance-id/
CompletableFuture<String> fut = new CompletableFuture<>();
JsonObject body = new JsonObject();
// JsonArray registration_ids = new JsonArray();
// body.put("registration_ids", registration_ids);
body.put("to", CLIENT_TOKEN);
body.put("priority", "high");
// body.put("dry_run", true);
JsonObject notification = new JsonObject();
notification.put("body", "body string here");
notification.put("title", "title string here");
// notification.put("icon", "myicon");
JsonObject data = new JsonObject();
data.put("key1", "value1");
data.put("key2", "value2");
body.put("notification", notification);
body.put("data", data);
HttpClientRequest hcr = httpsClient.post(443, host, requestURI).handler(response -> {
response.bodyHandler(buffer -> {
logger.debug("FcmTest1 rcvd: {}, {}", response.statusCode(), buffer.toString());
if (response.statusCode() == 200) {
fut.complete(buffer.toString());
} else {
fut.completeExceptionally(new RuntimeException(buffer.toString()));
}
});
});
hcr.putHeader("Authorization", "key=" + Utils.FIREBASE_SERVER_KEY)
.putHeader("content-type", "application/json").end(body.encode());
return fut;
}
note: http client and json were provided by vertx (http://vertx.io/), but hopefully the code shows what's going on clear enough so you can use whatever you wish.