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:
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.
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.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.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)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.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.
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.
-
Sign into your Google Play Dev Console and click the app you're setting up.
-
Visit Settings->API access
-
Under Service Accounts, hit the Create Service Account button.
-
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!
-
Now you're done with #4, you'll see your new Service Account listed; click "Grant Access" to enable it.
-
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 "Visibility" 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.
- Add the Android Publisher Client Library from Nuget[1]
PM> Install-Package Google.Apis.AndroidPublisher.v3
-
Add the P12 file to your project root
-
Change the P12 Properties so "Build Action" is "Content" and "Copy To Output Directory" to "Copy if newer".
-
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]
1 Updated 04/11/2020 - Google.Apis.AndroidPublisher.v2 EOL'd, use Google.Apis.AndroidPublisher.v3.