29

I'trying to use Google APIs Client Library for Java to get information about user's subscriptions purchased in my android app. Here is how I'm doing for now:

HttpTransport HTTP_TRANSPORT = new NetHttpTransport();
JsonFactory JSON_FACTORY = new JacksonFactory();

GoogleCredential credential = new GoogleCredential.Builder().setTransport(HTTP_TRANSPORT)
                    .setJsonFactory(JSON_FACTORY)
                    .setServiceAccountId(GOOGLE_CLIENT_MAIL)
                    .setServiceAccountScopes("https://www.googleapis.com/auth/androidpublisher")
                    .setServiceAccountPrivateKeyFromP12File(new File(GOOGLE_KEY_FILE_PATH))
                    .build();

Androidpublisher publisher = new Androidpublisher.Builder(HTTP_TRANSPORT, JSON_FACTORY, credential).
                    setApplicationName(GOOGLE_PRODUCT_NAME).
                    build();

Androidpublisher.Purchases purchases = publisher.purchases();
Get get = purchases.get("XXXXX", subscriptionId, token);
SubscriptionPurchase subscripcion = get.execute(); //Exception returned here

GOOGLE_CLIENT_MAIL is the email address from API Access from the Google Console. GOOGLE_KEY_FILE_PATH is the p12 file downloaded from the API Access.
GOOGLE_PRODUCT_NAME is the product name from the branding information.
In Google APIS Console the Service "Google Play Android Developer API" is enabled.

What I'm getting is:

{
  "code" : 401,
  "errors" : [ {
    "domain" : "androidpublisher",
    "message" : "This developer account does not own the application.",
    "reason" : "developerDoesNotOwnApplication"
  } ],
  "message" : "This developer account does not own the application."
}

I really appreciate your help for this issue...

Jonathan Naguin
  • 14,526
  • 6
  • 46
  • 75
  • I have some doubts. I stuck in that for a week. I am doing an app to get all reviews from a play store. It's for all end user who has an account in play store. https://developers.google.com/android-publisher/getting_started This document specifies that I need to create oAuth and I need to link project id in my developer console for accessing review API I tried that and its working fine. But for all end user its odd for them to create OAuth and link project id into their dev console and then accessing my app I don't get any solution if anyone knows please reply – Lavanya Velusamy May 09 '18 at 01:18

6 Answers6

48

I got it working! The steps I followed:

Prerequisite

Before start, we need to generate a refresh token. To do this first we have to create an APIs console project:

  1. Go to the APIs Console and log in with your Android developer account (the same account used in Android Developer Console to upload the APK).
  2. Select Create project.
  3. Go to Services in the left-hand navigation panel.
  4. Turn the Google Play Android Developer API on.
  5. Accept the Terms of Service.
  6. Go to API Access in the left-hand navigation panel.
  7. Select Create an OAuth 2.0 client ID:
    • On the first page, you will need to fill in the product name, but a logo is not required.
    • On the second page, select web application and set the redirect URI and Javascript origins. We will use it later the redirect URI.
  8. Select Create client ID. Keep in mind the Client ID and the Client secret, we will use them later.

So, now we can generate the refresh token:

  1. Go to the following URI (note that the redirect URI must match the value entered in the client ID exactly, including any trailing backslashes):

https://accounts.google.com/o/oauth2/auth?scope=https://www.googleapis.com/auth/androidpublisher&response_type=code&access_type=offline&redirect_uri=REDIRECT_URI&client_id=CLIENT_ID

  1. Select Allow access when prompted.
  2. The browser will be redirected to your redirect URI with a code parameter, which will look similar to 4/eWdxD7b-YSQ5CNNb-c2iI83KQx19.wp6198ti5Zc7dJ3UXOl0T3aRLxQmbwI. Copy this value.

Create a main class with:

public static String getRefreshToken(String code)
{

    HttpClient client = new DefaultHttpClient();
    HttpPost post = new HttpPost("https://accounts.google.com/o/oauth2/token");
    try 
    {
        List<NameValuePair> nameValuePairs = new ArrayList<NameValuePair>(5);
        nameValuePairs.add(new BasicNameValuePair("grant_type",    "authorization_code"));
        nameValuePairs.add(new BasicNameValuePair("client_id",     GOOGLE_CLIENT_ID));
        nameValuePairs.add(new BasicNameValuePair("client_secret", GOOGLE_CLIENT_SECRET));
        nameValuePairs.add(new BasicNameValuePair("code", code));
        nameValuePairs.add(new BasicNameValuePair("redirect_uri", GOOGLE_REDIRECT_URI));
        post.setEntity(new UrlEncodedFormEntity(nameValuePairs));

        org.apache.http.HttpResponse response = client.execute(post);
        BufferedReader reader = new BufferedReader(new InputStreamReader(response.getEntity().getContent()));
        StringBuffer buffer = new StringBuffer();
        for (String line = reader.readLine(); line != null; line = reader.readLine())
        {
            buffer.append(line);
        }

        JSONObject json = new JSONObject(buffer.toString());
        String refreshToken = json.getString("refresh_token");                      
        return refreshToken;
    }
    catch (Exception e) { e.printStackTrace(); }

    return null;
}

GOOGLE_CLIENT_ID, GOOGLE_CLIENT_SECRET and GOOGLE_REDIRECT_URI are the previously values.

Finally, we have our refresh token! This value does not expire, so we can store in some site, like a property file.

Accessing to Google Play Android Developer API

  1. Getting the access token. We will need our previosly refresh token:

    private static String getAccessToken(String refreshToken){
    
    HttpClient client = new DefaultHttpClient();
    HttpPost post = new HttpPost("https://accounts.google.com/o/oauth2/token");
    try 
    {
        List<NameValuePair> nameValuePairs = new ArrayList<NameValuePair>(4);
        nameValuePairs.add(new BasicNameValuePair("grant_type",    "refresh_token"));
        nameValuePairs.add(new BasicNameValuePair("client_id",     GOOGLE_CLIENT_ID));
        nameValuePairs.add(new BasicNameValuePair("client_secret", GOOGLE_CLIENT_SECRET));
        nameValuePairs.add(new BasicNameValuePair("refresh_token", refreshToken));
        post.setEntity(new UrlEncodedFormEntity(nameValuePairs));
    
        org.apache.http.HttpResponse response = client.execute(post);
        BufferedReader reader = new BufferedReader(new InputStreamReader(response.getEntity().getContent()));
        StringBuffer buffer = new StringBuffer();
        for (String line = reader.readLine(); line != null; line = reader.readLine())
        {
            buffer.append(line);
        }
    
        JSONObject json = new JSONObject(buffer.toString());
        String accessToken = json.getString("access_token");
    
        return accessToken;
    
    }
    catch (IOException e) { e.printStackTrace(); }
    
    return null;
    

    }

  2. Now, we can access to the Android API. I'm interesting in the expiration time of a subscription, so:

    private static HttpTransport HTTP_TRANSPORT = new NetHttpTransport();
    private static JsonFactory JSON_FACTORY = new com.google.api.client.json.jackson2.JacksonFactory();
    
    private static Long getSubscriptionExpire(String accessToken, String refreshToken, String subscriptionId, String purchaseToken){
    
    try{
    
        TokenResponse tokenResponse = new TokenResponse();
        tokenResponse.setAccessToken(accessToken);
        tokenResponse.setRefreshToken(refreshToken);
        tokenResponse.setExpiresInSeconds(3600L);
        tokenResponse.setScope("https://www.googleapis.com/auth/androidpublisher");
        tokenResponse.setTokenType("Bearer");
    
        HttpRequestInitializer credential =  new GoogleCredential.Builder().setTransport(HTTP_TRANSPORT)
                .setJsonFactory(JSON_FACTORY)
                .setClientSecrets(GOOGLE_CLIENT_ID, GOOGLE_CLIENT_SECRET)
                .build()
                .setFromTokenResponse(tokenResponse);
    
        Androidpublisher publisher = new Androidpublisher.Builder(HTTP_TRANSPORT, JSON_FACTORY, credential).
                setApplicationName(GOOGLE_PRODUCT_NAME).
                build();
    
        Androidpublisher.Purchases purchases = publisher.purchases();
        Get get = purchases.get(GOOGLE_PACKAGE_NAME, subscriptionId, purchaseToken);
        SubscriptionPurchase subscripcion = get.execute();
    
        return subscripcion.getValidUntilTimestampMsec();
    
    }
    catch (IOException e) { e.printStackTrace(); }
    return null;
    

    }

And that's all!

Some steps are from https://developers.google.com/android-publisher/authorization.

Jonathan Naguin
  • 14,526
  • 6
  • 46
  • 75
  • hello i have a problem to get an access and a refresh token. i have the code already but when i do a http post request to retrieve access or refresh token i got bad request error 400 or 'invalid_request'. – MOST2K2 Dec 29 '12 at 00:31
  • @Jonathan Naguin Which access are you passing while calling the Google Play purchace api? The user's access token or the developer's access token as I 'm getting an This developer account does not own the application error. – Searock Jun 25 '13 at 14:25
  • @Searock The access token passed at `getSubscriptionExpire` is the returned value from `getAccessToken` – Jonathan Naguin Jun 25 '13 at 14:35
  • 1
    Note that if you're using httpclient-4.2, you must specify encoding when creating the UrlEncodedFormEntity: `post.setEntity(new UrlEncodedFormEntity(nameValuePairs, "utf-8@));` Failing to do so results in a NullPointerException. – Josh Glover May 01 '14 at 09:41
  • For one-time use to obtain the refresh token, add to top of getRefreshToken: StrictMode.ThreadPolicy policy = new StrictMode.ThreadPolicy.Builder().permitAll().build(); StrictMode.setThreadPolicy(policy); – alice_silver_man May 28 '14 at 19:37
  • @Jonathan, oAuth code that we get from a browser, that we can use only one time, I run the same code on a different device it didn't work. so how I check subscription detail if I unable to get refresh token. – Harshvardhan Trivedi Aug 08 '15 at 09:41
  • 7
    I find it ridiculous how obtuse this process seems. The documentation for this is practically non-existent. For 'helper' libraries, having to dig through SO to even find a decent code example is ridiculous. Apple's documentation completely sucks, but at least the process is simple to validate receipts. /rant – Brian Dec 23 '15 at 22:44
  • https://stackoverflow.com/questions/50237872/publisher-api-without-oauth-of-developer-account – Lavanya Velusamy May 09 '18 at 01:17
  • I have some doubts. I stuck in that for a week. I am doing an app to get all reviews from a play store. It's for all end user who has an account in play store. https://developers.google.com/android-publisher/getting_started This document specifies that I need to create oAuth and I need to link project id in my developer console for accessing review API I tried that and its working fine. But for all end user its odd for them to create OAuth and link project id into their dev console and then accessing my app I don't get any solution if anyone knows please reply – Lavanya Velusamy May 09 '18 at 01:18
  • @Jonathan Naguin Can i pass developer access token to the api? To retrive users subscription expiry date using subscription token – Chetan Patil Jul 26 '19 at 02:22
  • I think it's much simpler to just create a service account and use it with its .p12 or .json file, like in @MihaHribar answer. – gscaparrotti Jul 06 '20 at 15:25
  • decoding of the code needed before fetching refresh_token or it will fail with "error": "invalid_grant", "error_description": "Malformed auth code." String decoded = URLDecoder.decode(codeFromRedirectURI, "UTF-8"); – itabdullah Sep 23 '20 at 12:32
9

You can use com.google.api-client and google-api-services-androidpublisher libraries.

First go to the project on google developer console (https://console.developers.google.com)

  • APIs & Auth -> APIs
  • Enable "Google Play Android Developer API"
  • Go to Credentials -> Create new Client ID
  • Select service account
  • Create client ID
  • Save the p12 file somewhere safe

Then add the just generated email address for the service account to your google play developer console (https://play.google.com/apps/publish/)

  • Settings -> Users and permissions -> Invite new users
  • Paste the @developer.gserviceaccount.com email account
  • Select "View financial reports"
  • Send invitation

Now to the code. Add the following dependencies to your pom.xml file:

<dependency>
    <groupId>com.google.api-client</groupId>
    <artifactId>google-api-client</artifactId>
    <version>1.18.0-rc</version>
</dependency>
<dependency>
    <groupId>com.google.http-client</groupId>
    <artifactId>google-http-client-jackson2</artifactId>
    <version>1.18.0-rc</version>
</dependency>
<dependency>
    <groupId>com.google.apis</groupId>
    <artifactId>google-api-services-androidpublisher</artifactId>
    <version>v1.1-rev25-1.18.0-rc</version>
</dependency>

Then first validate the signature:

byte[] decoded = BASE64DecoderStream.decode(KEY.getBytes());
KeyFactory keyFactory = KeyFactory.getInstance("RSA");
PublicKey publicKey = keyFactory.generatePublic(new X509EncodedKeySpec(decoded));
Signature sig = Signature.getInstance("SHA1withRSA");
sig.initVerify(publicKey);
sig.update(signedData.getBytes());
if (sig.verify(BASE64DecoderStream.decode(signature.getBytes())))
{
    // Valid
}

If the signature verifies fetch subscription details:

// fetch signature details from google
HttpTransport httpTransport = GoogleNetHttpTransport.newTrustedTransport();
JsonFactory jsonFactory = JacksonFactory.getDefaultInstance();
GoogleCredential credential = new GoogleCredential.Builder()
    .setTransport(httpTransport)
    .setJsonFactory(jsonFactory)
    .setServiceAccountId(ACCOUNT_ID)
    .setServiceAccountScopes(Collections.singleton("https://www.googleapis.com/auth/androidpublisher"))
    .setServiceAccountPrivateKeyFromP12File(new File("key.p12"))
    .build();

AndroidPublisher pub = new AndroidPublisher.Builder(httpTransport, jsonFactory, credential)
    .setApplicationName(APPLICATION_NAME)
    .build();
AndroidPublisher.Purchases.Get get = pub.purchases().get(
    APPLICATION_NAME,
    PRODUCT_ID,
    token);
SubscriptionPurchase subscription = get.execute();
System.out.println(subscription.toPrettyString());

This will take care of all the token issues by generating a JWT token so you don't have to handle it yourself.

Luciano
  • 1,119
  • 12
  • 18
Miha Hribar
  • 5,776
  • 3
  • 26
  • 24
  • 1
    This looks to be a great answer... but where did KEY come from? The JSON (not .p12) file Google sent me has a "private_key" that is in PKCS#8 format (i.e. has "-----BEGIN PRIVATE KEY-----" to start) and so I receive an `InvalidKeyException` with "algid parse error, not a sequence" during the `generatePublic()` call. I tried changing `X509EncodedKeySpec()` to `PKCS8EncodedKeySpec()` but I just get a different error: `InvalidKepSpecException` with "Only RSAPublicKeySpec and X509EncodedKeySpec supported for RSA public keys". Any ideas? – Brian White Aug 07 '14 at 03:42
  • 1
    I have some doubts. I stuck in that for a week. I am doing an app to get all reviews from a play store. It's for all end user who has an account in play store. https://developers.google.com/android-publisher/getting_started This document specifies that I need to create oAuth and I need to link project id in my developer console for accessing review API I tried that and its working fine. But for all end user its odd for them to create OAuth and link project id into their dev console and then accessing my app I don't get any solution if anyone knows please reply – Lavanya Velusamy May 09 '18 at 01:18
  • Just a little tip if someone gets the same error I got: if you get an exception while loading the .p12 file saying something like `DerInputStream.getLength(): lengthTag=111, too big.`, then make sure to exclude it from Maven filtering: https://stackoverflow.com/questions/17298126/generated-certificate-stops-working-when-moved-to-resources-folder – gscaparrotti Jul 06 '20 at 15:28
5

For those who want to check subscription status on Google's AppEngine with Java, here is my working example based on many codes found on SO. I spent couple of days to solve many mistakes caused by lack of experience. I see lot of suggestions to check subscription status on server but it was not easy for me to do on AppEngine. Without answers found on SO, I could not come up with this.

Step 1

First we need to go through "Prerequisite" section found on Jonathan Naguin's answer, until you get code from web browser. Now you have;

  • Client ID
  • Client secret
  • Redirect URI
  • code

ready.

Note we run all codes shown below on AppEngine. And I used logger like this.

static final Logger log = Logger.getLogger(MyClassName.class.getName());

Step 2

We need to get refresh token. Run code shown below after replacing [YOUR CLIENT ID], [YOUR CLIENT SECRET], [YOUR CODE], [YOUR REDIRECT URI] with your string.

private String getRefreshToken()
{
    try
    {
        Map<String,Object> params = new LinkedHashMap<>();
        params.put("grant_type","authorization_code");
        params.put("client_id",[YOUR CLIENT ID]);
        params.put("client_secret",[YOUR CLIENT SECRET]);
        params.put("code",[YOUR CODE]);
        params.put("redirect_uri",[YOUR REDIRECT URI]);

        StringBuilder postData = new StringBuilder();
        for(Map.Entry<String,Object> param : params.entrySet())
        {
            if(postData.length() != 0)
            {
                postData.append('&');
            }
            postData.append(URLEncoder.encode(param.getKey(),"UTF-8"));
            postData.append('=');
            postData.append(URLEncoder.encode(String.valueOf(param.getValue()),"UTF-8"));
        }
        byte[] postDataBytes = postData.toString().getBytes("UTF-8");

        URL url = new URL("https://accounts.google.com/o/oauth2/token");
        HttpURLConnection conn = (HttpURLConnection)url.openConnection();
        conn.setDoOutput(true);
        conn.setUseCaches(false);
        conn.setRequestMethod("POST");
        conn.getOutputStream().write(postDataBytes);

        BufferedReader  reader = new BufferedReader(new InputStreamReader(conn.getInputStream()));
        StringBuffer buffer = new StringBuffer();
        for (String line = reader.readLine(); line != null; line = reader.readLine())
        {
            buffer.append(line);
        }

        JSONObject json = new JSONObject(buffer.toString());
        String refreshToken = json.getString("refresh_token");
        return refreshToken;
    }
    catch (Exception ex)
    {
        log.severe("oops! " + ex.getMessage());
    }
    return null;
}

Since refresh token won't expire, we can save it somewhere or simply hard-code in our code. (We only need to run above code once to get refresh token.)

Step 3

We need to get access token. Run code shown below after replacing [YOUR CLIENT ID], [YOUR CLIENT SECRET], [YOUR REFRESH TOKEN] with your string.

private String getAccessToken()
{
    try
    {
        Map<String,Object> params = new LinkedHashMap<>();
        params.put("grant_type","refresh_token");
        params.put("client_id",[YOUR CLIENT ID]);
        params.put("client_secret",[YOUR CLIENT SECRET]);
        params.put("refresh_token",[YOUR REFRESH TOKEN]);

        StringBuilder postData = new StringBuilder();
        for(Map.Entry<String,Object> param : params.entrySet())
        {
            if(postData.length() != 0)
            {
                postData.append('&');
            }
            postData.append(URLEncoder.encode(param.getKey(),"UTF-8"));
            postData.append('=');
            postData.append(URLEncoder.encode(String.valueOf(param.getValue()),"UTF-8"));
        }
        byte[] postDataBytes = postData.toString().getBytes("UTF-8");

        URL url = new URL("https://accounts.google.com/o/oauth2/token");
        HttpURLConnection conn = (HttpURLConnection)url.openConnection();
        conn.setDoOutput(true);
        conn.setUseCaches(false);
        conn.setRequestMethod("POST");
        conn.getOutputStream().write(postDataBytes);

        BufferedReader  reader = new BufferedReader(new InputStreamReader(conn.getInputStream()));
        StringBuffer buffer = new StringBuffer();
        for (String line = reader.readLine(); line != null; line = reader.readLine())
        {
            buffer.append(line);
        }

        JSONObject json = new JSONObject(buffer.toString());
        String accessToken = json.getString("access_token");
        return accessToken;
    }
    catch (Exception ex)
    {
        log.severe("oops! " + ex.getMessage());
    }
    return null;
}

Step 4

What I wanted to know is just expire UTC of the subscription. Code shown below returns expire UTC, 0 when found error. You need to provide your package name, product id (=subscription id), access token you got on Step 3, and purchase token found in your purchase data.

private long getExpireDate(String packageName,String productId,String accessToken,String purchaseToken)
{
    try
    {
        String charset = "UTF-8";
        String query = String.format("access_token=%s",URLEncoder.encode(accessToken,charset));

        String path = String.format("https://www.googleapis.com/androidpublisher/v1/applications/%s/subscriptions/%s/purchases/%s",packageName,productId,purchaseToken);
        URL url = new URL(path + "?" + query);
        HttpURLConnection connection = (HttpURLConnection)url.openConnection();
        connection.setRequestProperty("Accept-Charset",charset);
        connection.setRequestMethod("GET");

        BufferedReader  reader = new BufferedReader(new InputStreamReader(connection.getInputStream()));
        StringBuffer buffer = new StringBuffer();
        for(String line = reader.readLine(); line != null; line = reader.readLine())
        {
            buffer.append(line);
        }

        JSONObject json = new JSONObject(buffer.toString());
        return json.optLong("validUntilTimestampMsec");
    }
    catch (Exception ex)
    {
        log.severe("oops! " + ex.getMessage());
    }
    return 0;
}

Note product id or subscription id is a string found on developer console. Your subscription item appears with name/id column. It looks like this.

Description of item(product id)

Last step (fun part)

Now we have all components to verify subscription is valid or not. I did like this. You need to replace [YOUR PACKAGE NAME], [YOUR PRODUCT ID] with yours.

You need to provide purchase data which you can get with Purchase#getOriginalJson() found in iabHelper code.

private boolean checkValidSubscription(String purchaseData)
{
    String purchaseToken;
    JSONObject json;
    try
    {
        json = new JSONObject(purchaseData);
    }
    catch (JSONException e)
    {
        log.severe("purchaseData is corrupted");
        return true;    // false positive
    }
    purchaseToken = json.optString("purchaseToken");
    if(purchaseToken.length() == 0)
    {
        log.severe("no purchase token found");
        return true;    // false positive
    }
    String accessToken = getAccessToken();
    if(accessToken == null)
    {
        return true;    // false positive
    }
    long expireDate = getExpireDate([YOUR PACKAGE NAME],[YOUR PRODUCT ID],accessToken,purchaseToken);
    if(expireDate == 0)
    {
        log.severe("no expire date found");
        return true;    // false positive
    }
    expireDate += 86400000l;    // add one day to avoid mis judge
    if(expireDate  < System.currentTimeMillis())
    {
        log.severe("subscription is expired");
        return false;
    }
    // just for log output
    long leftDays = (expireDate - System.currentTimeMillis()) / 86400000l;
    log.info(leftDays + " days left");
    return true;
}

Note for debugging

Google returns JSON string for response. If code won't work as expected, logging JSON string may help understanding what is wrong.

I hope this helps someone.

Tomcat
  • 1,405
  • 3
  • 22
  • 37
  • I have some doubts. I stuck in that for a week. I am doing an app to get all reviews from a play store. It's for all end user who has an account in play store. https://developers.google.com/android-publisher/getting_started This document specifies that I need to create oAuth and I need to link project id in my developer console for accessing review API I tried that and its working fine. But for all end user its odd for them to create OAuth and link project id into their dev console and then accessing my app I don't get any solution if anyone knows please reply – Lavanya Velusamy May 09 '18 at 01:18
4

To piggyback on Jonathan Naguin's great answer, here is a nodejs version of getting the refresh and access token:

//This script is to retreive a refresh token and an access token from Google API. 
//NOTE: The refresh token will only appear the first time your client credentials are used. 
//      I had to delete my client id within api console and create a new one to get the refresh token again.

//This is the downloaded json object from Google API Console. Just copy and paste over the template below.
var googleJson = {"web":{"auth_uri":"","client_secret":"","token_uri":"","client_email":"","redirect_uris":[""],"client_x509_cert_url":"","client_id":"","auth_provider_x509_cert_url":"","javascript_origins":[""]}};

//Retrieved from OAuth
var code            = ''; // Retrieved from the response of the URL generated by printGoogleAuthUrl(). You will need to be logged in as your publisher. Copy and paste the generated url. Copy the code parameter into this variable.
var refreshToken    = ''; // Retrieved from the printRefreshToken() function call. Requires the code variable to be filled out.
var accessToken     = ''; // Retrieved from the printAccessToken() function call. Requires the refreshToken variable to be filled out.


var querystring = require('querystring');
var https = require('https');
var fs = require('fs');

function printGoogleAuthUrl()
{
    console.log("https://accounts.google.com/o/oauth2/auth?scope=https://www.googleapis.com/auth/androidpublisher&response_type=code&access_type=offline&redirect_uri=" + googleJson.web.redirect_uris[0] + "&client_id=" + googleJson.web.client_id);
}

function printRefreshToken()
{
    var post_data = querystring.stringify({
        'grant_type'    : 'authorization_code',
        'client_id'     : googleJson.web.client_id,
        'client_secret' : googleJson.web.client_secret,
        'code'          : code,
        'redirect_uri'  : googleJson.web.redirect_uris[0]
    });

    var post_options = {
      host: 'accounts.google.com',
      port: '443',
      path: '/o/oauth2/token',
      method: 'POST',
      headers: {
          'Content-Type': 'application/x-www-form-urlencoded',
          'Content-Length': post_data.length
        }
    };

    var post_req = https.request(post_options, function(res) {
        res.setEncoding('utf8');
        var data = "";
        res.on('data', function (chunk) {
            data += chunk;
        });

        res.on('end', function(){
            var obj = JSON.parse(data);
            if(obj.refresh_token)
            {
                refreshToken = obj.refresh_token;
            }
            else
            {
                console.log("No refresh token found. I had to clear the web client id in Google Api Console and create a new one. There might be a better way here.");
            }   

            console.log(data);

        });
    });

    post_req.write(post_data);
    post_req.end();
}

function printAccessToken()
{
    var post_data = querystring.stringify({
        'grant_type'    : 'refresh_token',
        'client_id'     : googleJson.web.client_id,
        'client_secret' : googleJson.web.client_secret,
        'refresh_token' : refreshToken
    });

    var post_options = {
      host: 'accounts.google.com',
      port: '443',
      path: '/o/oauth2/token',
      method: 'POST',
      headers: {
          'Content-Type': 'application/x-www-form-urlencoded',
          'Content-Length': post_data.length
        }
    };

    var post_req = https.request(post_options, function(res) {
        res.setEncoding('utf8');
        var data = "";
        res.on('data', function (chunk) {
            data += chunk;
        });

        res.on('end', function(){
            var obj = JSON.parse(data);
            if(obj.access_token)
                accessToken = obj.access_token;
            else
                console.log("No access token found.");

            console.log(data);

        });
    });

    post_req.write(post_data);
    post_req.end();
}

printGoogleAuthUrl();
//printRefreshToken();  
//printAccessToken();
KoboldAtWork
  • 131
  • 1
  • 3
  • I have some doubts. I stuck in that for a week. I am doing an app to get all reviews from a play store. It's for all end user who has an account in play store. https://developers.google.com/android-publisher/getting_started This document specifies that I need to create oAuth and I need to link project id in my developer console for accessing review API I tried that and its working fine. But for all end user its odd for them to create OAuth and link project id into their dev console and then accessing my app I don't get any solution if anyone knows please reply – Lavanya Velusamy May 09 '18 at 01:18
2

For those looking for a more up-to-date answer with AndroidPublisher v3 please look here: https://stackoverflow.com/a/57943483/1028256.

No need to deal with refreshToken & accessToken, and just few lines of code.

For Android client I found this 'official' sample code: https://github.com/googlesamples/android-play-publisher-api/blob/master/v3/java/src/com/google/play/developerapi/samples/AndroidPublisherHelper.java and there are options to get AndroidPublisher both with .p12 file or the app credentials.

Mixaz
  • 4,068
  • 1
  • 29
  • 55
-1

I'm pretty sure you have to use your Client ID, not the email address. It looks like this: 37382847321922.apps.googleusercontent.com

See https://developers.google.com/android-publisher/authorization

client_id=<the client ID token created in the APIs Console>

And I'm pretty sure you don't need a P12 file. You only need the

client_secret=<the client secret corresponding to the client ID>

Try doing it manually from the command line first, with 'wget'.

Chloe
  • 25,162
  • 40
  • 190
  • 357