TL;DR To programatically verify Google Play subscriptions, you have to use the OAuth 2.0 for web server applications auth flow, not service accounts. This is a massive FUBAR on Google’s side and makes life of developers very painful.
Lately, I’ve been working on the backend part of a upcoming app we’re developing for one of our clients. This app offers monthly and yearly subscriptions, so I had to implement a check if the recurring payment happened, the credit card got billed and the app provider got the money. Of course, for multiple reasons, this has to be done server-side, completely automatically and without any intervention from the app user or provider.
Google provides an API called android-publisher for this. To use any API from Google, first you have to enable it from the Console and then authenticate with it. The authentication is done via OAuth 2.0. As Google offers API access to many of their services which are used in different occasions, they also offer different OAuth 2.0 authentication flows.
The flow/mechanism for server to server communication is called Service accounts in Google terminology. This is precisely what I needed. However, for reasons beyond my understanding, this is not the one used for android-publisher API. Instead, they chose Web server applications flow, which for this use case is absurd.
(Sidenote: When we started to build the aforementioned app, recurring transaction were not even available for Android. We planned to use Paypal as we did for the Blackberry version. However, during development, Google introduced subscriptions for Android which made us happy.
I started reading the docs and implementing the whole auth and check code, but it didn’t work; I was getting “This developer account does not own the application.” HTTP 401 error. Googling for this didn’t help – at that time, the only search results were two couple of hours old questions on Stack Overflow. I would swear the docs at that time mentioned to use Service accounts for authentication and later Google changed it. I had to re-read the docs from the beginning to debug this infuriating error.)
Using Web server applications flow is ridiculous because human interaction is involved. At least once, you (in this case our client!) need to press an “Allow” button in you web browser. Palm, meet face.
Here are the instructions you need to follow to achieve automated subscription verification. The code is in Python but it’s easy to adapt.
First of all, in the Console, you need to create a Client ID for Web applications. You can use http://localhost
as the redirect hostname. As you’ll see in a minute, it doesn’t matter much. You mostly need the Client ID and Client secret.
Next, fire up the Python REPL and enter this:
https://gist.github.com/3450666
Use the Client ID and Client secret you obtained from Console. This piece of code will give you an authentication URL; by default, it will contain access_type=offline
parameter. This is very important, make sure it’s there. Open the URL in your browser and log in with the Google account that you will be using for publishing the Android application. After a successfull login and authorization, you’ll be redirected to localhost in your browser. Unless you’re running a webserver locally, this will probably fail, but it doesn’t matter. The address you are redirected to will contain a code
parameter. Copy its value and go back to the REPL again:
https://gist.github.com/3450785
Finally you’ve got an instance of the oauth2client.client.OAuth2Credentials
class. It contains couple of properties but the only one that’s really interesting is the refresh_token
. Store the refresh token to your server configuration, you can use it forever meaning until someone does not revoke the access to the API. Then you would have to got through this whole process again.
Basically, thanks to this refresh token you will able to obtain a new access token on each call to the API. To do that, you create an instance of OAuth2Credentials
and use that to authorize an httplib2.Http
object:
https://gist.github.com/3451039
You can now build a service and call the get purchases API call.
The following gist summarizes the whole blogpost:
https://gist.github.com/3451509
As long as the API access will not be revoked, you should be fine using this method.
Hey,thank you much for this clear résumé. I spent already hours on how to figure out to get it running, but failed for same reasons.Nevertheless it is still total pain in the ass – and I really won’t understand why the hack google implemented their API this way, because it is not usable at all.Anyhow, could you already find a better approach in the meantime?I still need to do this automated, I’m already thinking about doing the initial activation programmatically (with wget or whatsoever, if it’s even possible), but, indeed, this is disappointing me totally.Cheers,Christopher
Hey,Thanks for the great post.I have left this issue cause I didn’t understand the "developer does’nt own…" error.I have some other issue,in the console I don’t an option for "Service account" in the api access,so I don’t have any option to enter any redirect URL. am I missing something?10x
Christopher: After implementing this solution, I didn’t touch it again or searched for another way around. I’m afraid Google won’t improve it either. I’ve raised the issue with them through several channels and I haven’t heard back so far.O2d2: When you log in to the Google API Console, select the "API Access" tab from the left-hand navigation. There you need to generate the Client ID for Web applications. It is there where you can enter the redirect URL.
Thanks for this Christopher, here’s a Ruby implementation based on your implementation: https://gist.github.com/cornflakesuperstar/5632813
This gist was updated due to a renamed github account, it’s now at: https://gist.github.com/jkotchoff/5632813
Hi any one can help me to acheive the same result using java for service account rather than using python .
Great article. Thank you Jason and Christopher. I was actually able to get this working with a service account in Ruby with your help. I described the flow here. It took me awhile to get this working
http://stackoverflow.com/questions/25828491/android-verify-iap-subscription-server-side-with-ruby/25903570#25903570
This seems to rely on the google app sending the server a renewed purchase token. Is there a way for the server to get the latest purchase token (or latest expiration time) without having the mobile app send it first.
Awesome reference thanks! I’d been struggling figuring this OAuth stuff out for most of the day when I stumbled upon your blog. It might be useful to also mention to use .to_json() to get the relevant information out of step 2. We can also use .from_json() to re-hydrate the credential blob:
credentials = flow.step2_exchange(code) # code from the localhost redirect
print (credentials.to_json())
Darn. I thought I’d figured this out when I posted my previous message. Unfortunately my refresh_token always comes back as null. I’m not sure what I’m doing wrong