Skip to content

Instantly share code, notes, and snippets.

@jhannes
Last active June 23, 2021 20:09
Show Gist options
  • Save jhannes/831cf19282576ff93ba25240b1f57c19 to your computer and use it in GitHub Desktop.
Save jhannes/831cf19282576ff93ba25240b1f57c19 to your computer and use it in GitHub Desktop.
Firebase Cloud Messaging sender client in java
import org.jsonbuddy.JsonNode;
import org.jsonbuddy.JsonObject;
import java.io.FileInputStream;
import java.io.IOException;
import java.io.OutputStreamWriter;
import java.net.HttpURLConnection;
import java.net.URL;
import java.nio.charset.StandardCharsets;
import java.security.GeneralSecurityException;
import java.security.KeyFactory;
import java.security.NoSuchAlgorithmException;
import java.security.PrivateKey;
import java.security.Signature;
import java.security.spec.InvalidKeySpecException;
import java.security.spec.PKCS8EncodedKeySpec;
import java.util.Base64;
public class FcmSender {
private static final String MESSAGING_SCOPE = "https://www.googleapis.com/auth/firebase.messaging";
private static final String[] SCOPES = {MESSAGING_SCOPE};
private String projectId;
public String keyId;
public static Base64.Encoder base64Encoder = Base64.getUrlEncoder();
private String clientEmail;
private PrivateKey privateKey;
public static void main(String[] args) throws IOException, GeneralSecurityException {
JsonObject serviceAccount = JsonObject.read(new FileInputStream("service-account.json"));
FcmSender fcmSender = new FcmSender();
fcmSender.setClientEmail(serviceAccount.requiredString("client_email"));
fcmSender.setProjectId(serviceAccount.requiredString("project_id"));
fcmSender.setKeyId(serviceAccount.requiredString("private_key_id"));
fcmSender.setPrivateKey(serviceAccount.requiredString("private_key"));
String clientToken = "....";
fcmSender.send(clientToken, "Hello", "Message");
}
private void send(String clientToken, String title, String message) throws IOException, GeneralSecurityException {
HttpURLConnection connection = (HttpURLConnection) new URL("https://fcm.googleapis.com/v1/projects/" + projectId + "/messages:send").openConnection();
connection.setRequestProperty("Authorization", "Bearer " + getAccessToken());
connection.setRequestProperty("Content-Type", "application/json; UTF-8");
connection.setDoOutput(true);
try (OutputStreamWriter writer = new OutputStreamWriter(connection.getOutputStream(), StandardCharsets.UTF_8)) {
writer.write(createMessage(clientToken, title, message).toString());
}
JsonObject response = JsonObject.read(connection);
System.out.println(response);
}
private JsonObject createMessage(String clientToken, String title, String body) {
return new JsonObject().put("message", new JsonObject()
.put("notification", new JsonObject()
.put("title", title)
.put("body", body))
.put("token", clientToken));
}
private String getAccessToken() throws IOException, GeneralSecurityException {
HttpURLConnection connection = (HttpURLConnection) new URL("https://oauth2.googleapis.com/token").openConnection();
connection.setRequestMethod("POST");
connection.setDoOutput(true);
connection.getOutputStream().write(
("grant_type=urn:ietf:params:oauth:grant-type:jwt-bearer" +
"&assertion=" + getJwtAssertion()).getBytes(StandardCharsets.UTF_8));
JsonObject tokenResponse = JsonObject.read(connection);
return tokenResponse.requiredString("access_token");
}
private String getJwtAssertion() throws GeneralSecurityException {
JsonObject jwtHeader = new JsonObject()
.put("alg", "RS256")
.put("typ", "JWT")
.put("kid", keyId);
JsonObject jwtPayload = new JsonObject()
.put("aud", "https://oauth2.googleapis.com/token")
.put("iss", clientEmail)
.put("scope", String.join(" ", SCOPES))
.put("iat", System.currentTimeMillis() / 1000)
.put("exp", System.currentTimeMillis() / 1000 + 3600);
return createSignedJwt(jwtHeader, jwtPayload, privateKey);
}
private static String createSignedJwt(JsonObject jwtHeader, JsonObject jwtPayload, PrivateKey privateKey) throws GeneralSecurityException {
String jwtContent = base64Encode(jwtHeader) + "." + base64Encode(jwtPayload);
Signature signature = Signature.getInstance("SHA256withRSA");
signature.initSign(privateKey);
signature.update(jwtContent.getBytes());
return jwtContent + "." + base64Encode(signature.sign());
}
public void setProjectId(String projectId) {
this.projectId = projectId;
}
public void setClientEmail(String clientEmail) {
this.clientEmail = clientEmail;
}
public void setKeyId(String keyId) {
this.keyId = keyId;
}
private void setPrivateKey(String privateKey) throws NoSuchAlgorithmException, InvalidKeySpecException {
privateKey = privateKey
.replace("-----BEGIN PRIVATE KEY-----", "")
.replace("-----END PRIVATE KEY-----", "")
.replace("\n", "");
setPrivateKey(Base64.getDecoder().decode(privateKey));
}
private void setPrivateKey(byte[] bytes) throws NoSuchAlgorithmException, InvalidKeySpecException {
setPrivateKey(KeyFactory.getInstance("RSA").generatePrivate(new PKCS8EncodedKeySpec(bytes)));
}
private void setPrivateKey(PrivateKey privateKey) {
this.privateKey = privateKey;
}
private static String base64Encode(JsonNode json) {
return base64Encode(json.toString().getBytes(StandardCharsets.UTF_8));
}
private static String base64Encode(byte[] bytes) {
return base64Encoder.encodeToString(bytes);
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment