Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How can I send a message to a device using C2DM from a server that has been authenticated with OAuth2?

I'm developing the server part of a system that has to send messages to a device. This was working fine with the GoogleLogin method, but I want to migrate it to OAuth 2.0 since the other authentication method has been deprecated.

In the Google API console I created a project and then I created a key for a service account.

This is the code I'm using to authenticate the server:

public boolean authenticateServer(){
    try {
        File privateKey =
            new File(getClass().getResource("/something-privatekey.p12").toURI());

        GoogleCredential cred =
            new GoogleCredential.Builder().setTransport(new NetHttpTransport())
                .setJsonFactory(new JacksonFactory())
                .setServiceAccountId("[email protected]")
                .setServiceAccountScopes("https://android.apis.google.com/c2dm")
                .setServiceAccountPrivateKeyFromP12File(privateKey)
                .addRefreshListener(this)
                .build();

        boolean success = cred.refreshToken();
        this.credential = cred;
        return success;        
    }
    catch (Exception ex) {
         //handle this
    }
    return false;
}

When I execute this, the method onTokenResponse gets called and I get an access_token with token_type "Bearer" expiring in 3600 seconds. So far, so good.

This is the code I'm using to send the message to the device, which is always giving me a 401 status (not authorized). Any ideas?

private static String UTF8 = "UTF-8";
public void sendMessage(String text, String registrationId) {
    try {
        StringBuilder postDataBuilder = new StringBuilder();
        postDataBuilder
            .append("registration_id")
            .append("=")
            .append(registrationId);

        postDataBuilder.append("&")
            .append("collapse_key")
            .append("=")
            .append("0");

        postDataBuilder.append("&")
            .append("data.payload")
            .append("=")
            .append(URLEncoder.encode(text, UTF8));

        byte[] postData = postDataBuilder.toString().getBytes(UTF8);

        URL url = new URL("https://android.apis.google.com/c2dm/send");

        HostnameVerifier hVerifier = new HostnameVerifier() {
            public boolean verify(String hostname, SSLSession session) {
                return true;
            }
        };

        HttpsURLConnection conn = (HttpsURLConnection) url.openConnection();
        conn.setHostnameVerifier(hVerifier);
        conn.setDoOutput(true);
        conn.setUseCaches(false);
        conn.setRequestMethod("POST");
        conn.setRequestProperty(
            "Content-Type", "application/x-www-form-urlencoded");
        conn.setRequestProperty(
            "Content-Length", Integer.toString(postData.length));
        conn.setRequestProperty(
            "Authorization", "Bearer " + credential.getAccessToken());

        OutputStream out = conn.getOutputStream();
        out.write(postData);
        out.close();
        int sw = conn.getResponseCode();
        System.out.println("" + sw);
    }
    catch (IOException ex){
        //handle this
    }
}

Thanks!

like image 444
gcesarmza Avatar asked Nov 03 '22 23:11

gcesarmza


1 Answers

Since C2DM is in a beta status as of now, the only way to make it work using OAuth2.0 is to create a Web application client Id, instead of a Service account (in the Google APIs console).

I've followed the steps in http://michsan.web.id/content/how-code-android-c2dm-oauth-2 and it worked perfectly

like image 106
gcesarmza Avatar answered Nov 09 '22 10:11

gcesarmza