Am I getting the steps right for verifying a user's Android in-app subscription?

As it turns out, my steps were not correct. It took me weeks to figure this out and it doesn't seem to be documented anywhere else. You're welcome:

  1. Create a Web Application account in the Google APIs Console. Put any website as a "redirect URI"; it doesn't matter since you will not really be using it. You will get a client id and client secret when you create the account.

  2. In a browser on your computer go to https://accounts.google.com/o/oauth2/auth?scope=https://www.googleapis.com/auth/androidpublisher&response_type=code&access_type=offline&redirect_uri=[YOUR REDIRECT URI]&client_id=[YOUR CLIENT ID] and allow access when prompted.

  3. Look in the address bar. At the end of the URI you entered originally will be your refresh token. It looks like 1/.... You will need this "code" in the next step. The refresh token never expires.

  4. Convert this "code" to a "refresh token" by going to https://accounts.google.com/o/oauth2/token?client_id=[YOUR CLIENT ID]&client_secret=[YOUR CLIENT SECRET]&code=[CODE FROM PREVIOUS STEP]&grant_type=authorization_code&redirect_uri=[YOUR REDIRECT URI]. You can save the resulting value right in your program; it never expires unless explicitly revoked. (this step inserted by @BrianWhite -- see comments) Make sure you are using POST.(inserted by Gintas)

  5. In your code, send an HttpPost request to https://accounts.google.com/o/oauth2/token with the BasicNameValuePairs "grant_type","refresh_token", "client_id",[YOUR CLIENT ID], "client_secret",[YOUR CLIENT SECRET], "refresh_token",[YOUR REFRESH TOKEN]. For an example look here. You will need to do this in a separate thread, probably using AsyncTask. This will return a JSONObject.

  6. Get the access token from the returned JSONObject. For an example look here. You will need to get the string "access_token". The access token expires in 1 hour.

  7. In your code, send an HttpGet request to https://www.googleapis.com/androidpublisher/v1/applications/[YOUR APP'S PACKAGE NAME]/subscriptions/[THE ID OF YOUR PUBLISHED SUBSCRIPTION FROM YOUR ANDROID DEVELOPER CONSOLE]/purchases/[THE PURCHASE TOKEN THE USER RECEIVES UPON PURCHASING THE SUBSCRIPTION]?accesstoken="[THE ACCESS TOKEN FROM STEP 4]". For an example look here.


.NET Users: I hope this answer saves someone a ton of grief.

As @Christophe Fondacci noted on 2015, the accepted solution worked great a few years ago.

Now it's 2017 2020 and the process is far easier and faster.

My use case is to validate in-app subscriptions, where my mobile app sends subscription purchase information to my RESTful server, which in turn contacts Google to validate a subscription purchase.

The strategy is to create a Service Account that will operate on your behalf.

  1. Sign into your Google Play Dev Console and click the app you're setting up.
  2. Visit Settings->API access
  3. Under Service Accounts, hit the Create Service Account button.
  4. As of Jan 2017 a dialog with directions on setting up a service account appears. The dialog takes you to the Google API Console; from there,

    A) Click Create Service Account

    B) Create the service account name that makes sense. Since we're interested in accessing Android Publisher Services, I chose "publisher".

    C) For Role, just choose something - you can change this later.

    D) Choose "Furnish New private key" and choose P12 for .Net implementations. Don't lose this file!

5) Now you're done with #4, you'll see your new Service Account listed; click "Grant Access" to enable it.

6) Tap on the link to "View permissions". You should modify permissions based on your needs and API.

To validate in-app purchases, visit the Cog->Change Permissions and enable the GLOBAL "Visiblity" and "Manage Orders" permissions.

OK at this point you have configured everything on Google's end. Now to setup your server to server stuff. I recommend creating a .Net Console App to test out your implementation then offload it where needed.

1) Add the Android Publisher Client Library from Nuget[1]

PM> Install-Package Google.Apis.AndroidPublisher.v3

2) Add the P12 file to your project root

3) Change the P12 Properties so "Build Action" is "Content" and "Copy To Output Directory" to "Copy if newer".

4) Implement something like this to test your access and fine tune [1] .

using System.Threading.Tasks;
using System.Security.Cryptography.X509Certificates;
using Google.Apis.Services;
using Google.Apis.Auth.OAuth2;
using Google.Apis.AndroidPublisher.v3;
...
public Task<SubscriptionPurchase> GetSubscriptionPurchase(string packageName, string productId, string purchaseToken)
{
    var certificate = new X509Certificate2(
                    "{{your p12 file name}}",
                    "{{ your p12 secret }}",
                    X509KeyStorageFlags.Exportable
                );
    var credentials = new ServiceAccountCredential(
            new ServiceAccountCredential.Initializer("{{ your service account email }}")
            {
                Scopes = new[] { AndroidPublisherService.Scope.Androidpublisher }
            }.FromCertificate(certificate))
            ;

    var service = new AndroidPublisherService(new BaseClientService.Initializer()
    {
        HttpClientInitializer = credentials,
        ApplicationName = "my server app name",
    });
    return service.Purchases.Subscriptions.Get(packageName, productId, purchaseToken).ExecuteAsync();
}

Good luck, hope this helps someone.

Sources:

Using OAuth 2.0 for Server to Server Applications

.Net Client Library for Google.Apis.AndroidPublisher.v3[1]


Updated 04/11/2020 - Google.Apis.AndroidPublisher.v2 EOL'd, use Google.Apis.AndroidPublisher.v3.


If you are like me, and want to do this in PHP, here is the procedure how to do it... Thanks to Kalina's answer it took me only three days to work out how it works :).

Here goes:

  1. go to google developers console https://console.developers.google.com/ and create a web app. Put 'developers.google.com/oauthplayground'as a "redirect URI"; You will use it in step 2. You will get a client id and client secret when you create the account. Make sure you have the Google Play Android Developer API added.

  2. go to the Google oauth2 playground https://developers.google.com/oauthplayground/. This great tool is your best friend for the next few days. Now go to settings : make sure Use your own OAuth credentials is set. Only then you can fill in your client ID and client secret in the form below.

  3. In Google oauth2 playground go to step 1 Select & authorize APIs fill in the scope in the input field https://www.googleapis.com/auth/androidpublisher. I couldnt find the Google Play Android Developer API in the list, maybe they will add some time later. Hit AUTORIZE APIS. Do the authorisation thing that follows.

  4. In Google oauth2 playground go to step 2 Exchange authorization code for tokens. If all went well you will see a authorization code starting with /4. If something didnt go well check the error message on the right. Now you hit 'refresh access token'. Copy the Refresh token... it will start with /1...

  5. Now you can always get an access token! here is how:

    $url ="https://accounts.google.com/o/oauth2/token";
    $fields = array(
       "client_id"=>"{your client id}",
       "client_secret"=>"{your client secret}",
       "refresh_token"=>"{your refresh token 1/.....}",
       "grant_type"=>"refresh_token"
    );
    
    $ch = curl_init($url);
    
    //set the url, number of POST vars, POST data
    curl_setopt($ch, CURLOPT_POST,count($fields));
    curl_setopt($ch, CURLOPT_POSTFIELDS, $fields);
    curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, false);
    curl_setopt($ch, CURLOPT_SSL_VERIFYHOST, false);
    curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
    
    //execute post
    $lResponse_json = curl_exec($ch);
    
    //close connection
    curl_close($ch);
    

Now you have an ACCESS TOKEN hooray... the JSON will look like this:

"access_token" : "{the access token}",  "token_type" : "Bearer",  "expires_in" : 3600

Finally you're ready to ask google something! Here is how to do it:

$lAccessToken = "{The access token you got in}" ;
$lPackageNameStr = "{your apps package name com.something.something}";
$lURLStr =  "https://www.googleapis.com/androidpublisher/v1.1/applications/$lPackageNameStr/subscriptions/$pProductIdStr/purchases/$pReceiptStr";

$curl = curl_init($lURLStr);

curl_setopt($curl, CURLOPT_HTTPAUTH, CURLAUTH_ANY);
curl_setopt($curl, CURLOPT_SSL_VERIFYPEER, false);
curl_setopt($curl, CURLOPT_RETURNTRANSFER, 1); 
$curlheader[0] = "Authorization: Bearer " . $lAccessToken;
curl_setopt($curl, CURLOPT_HTTPHEADER, $curlheader);

$json_response = curl_exec($curl);
curl_close($curl);

$responseObj = json_decode($json_response,true);

The JSON returned will contain two timestamps, the initiationTimestampMsec and validUntilTimestampMsec the time the subscription is valid. Both are the nr of millisecs to add to the date 1/1/1970!