Ikai Lan says

I say things!

Setting up an OAuth provider on Google App Engine

with 25 comments

App Engine provides an API for easily creating an OAuth provider. In this blog post, I’ll describe the following steps:

  1. Create and deploy an App Engine application the implements the OAuth API
  2. Add a new domain to your Google Account. Verify this domain.
  3. Connecting an OAuth client to make requests against your application

I’ll avoid a deep explanation of OAuth for now. We can find everything you need to know about OAuth in the Beginner’s guide to OAuth.

Get the code

The code that goes along with this blog post is available here:

https://github.com/ikai/appengine-oauth-java-server-python-client-sample

The two most important files are:

  • python/oauth_client.py
  • src/com/ikai/oauthprovider/ProtectedServlet.java

Step 1: Create and deploy an App Engine application that uses the OAuth API

Create a new App Engine Java application. I’ve created a servlet called ProtectedServlet:

package com.ikai.oauthprovider;

import com.google.appengine.api.oauth.OAuthRequestException;
import com.google.appengine.api.oauth.OAuthService;
import com.google.appengine.api.oauth.OAuthServiceFactory;
import com.google.appengine.api.users.User;

import java.io.IOException;

import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

@SuppressWarnings("serial")
public class ProtectedServlet extends HttpServlet {
    
    @Override
    public void doGet(HttpServletRequest req, HttpServletResponse resp)
	    throws IOException {
	User user = null;
	try {
	    OAuthService oauth = OAuthServiceFactory.getOAuthService();
	    user = oauth.getCurrentUser();
	    resp.getWriter().println("Authenticated: " + user.getEmail());
	} catch (OAuthRequestException e) {
	    resp.getWriter().println("Not authenticated: " + e.getMessage());
	}
    }
    
}

This servlet is incredibly simple. We retrieve an instance of OAuthService via OAuthServiceFactory and attempt to fetch the current user. Note that the User instance is the same kind of instance as a User returned by UserService. That’s because a User is still expected to sign in via a Google Account.

The method getCurrentUser() takes care of all of the OAuth signature verification. If something goes wrong – say, the request is not signed, or the signature is invalid, or the client’s timestamp is outside of the acceptable skew, or the nonce is repeated – OAuthService throws OAuthRequestException.

We can run this code locally, but it won’t work. When run locally, oauth.getCurrentUser() always returns a test user. Wel need to deploy it to App Engine before it’ll do verification. After deploy, we can test the servlet. I have the servlet mapped to /resource. When we browse to this URL, we see:

Not authenticated: Unknown

That’s okay. We expect to see this because we’re sending a vanilla GET to this API.

2. Add a new domain to your Google Account. Verify this domain

OAuth clients require a consumer key and consumer token. We need to generate these. Browse to the “Manage Domains” page:

https://www.google.com/accounts/ManageDomains

It should look like this:

Add the base URL of our App Engine app into the text box in the “Add a New Domain” section and click “Add domain”. For instance, I entered: http://ikai-oauth.appspot.com.

We’ll be taken to a new page where we need to verify ownership of the application:

Download the HTML verification file and place it into our war directory. Deploy this new version of the application to App Engine. Once we have confirmed that the page is serving, click “Verify” to complete the verification process.

When we have verified our domain, we will be asked to accept the Terms of Service and enter a few settings. Only the authsub setting is required; we can enter anything we want here because we will not be using authsub. We will then be presented with an OAuth consumer key and OAuth consumer secret. The OAuth consumer key is simply the domain, whereas the consumer secret is an autogenerated shared secret that clients will be using.

Now we have these values, we can move on to step 3.

3. Connecting an OAuth client to make requests against your application

As of the time of this writing, App Engine only supports OAuth 1.0.

Below is a basic script that will do the 3-legged OAuth dance, cache access tokens locally and make API calls. To run this script, you will need to install the python-oauth2 library. If we have git installed, the commands to install the library on a *Nix like system are:

git clone https://github.com/simplegeo/python-oauth2.git
cd python-oauth2
sudo python setup.py install

This installs the oauth2 library into your Python install so you can import it when we need it.

Now we can run the script to make authenticated calls against our app. Note that we’ll want to substitute the consumer_secret and app_id values with values that map to your application ID and consumer secret:

import oauth2 as oauth
import urlparse
import os
import pickle

app_id = "your_app_id_here"
url = "http://%s.appspot.com/resource" % app_id

consumer_key = '%s.appspot.com' % app_id
consumer_secret = 'your_consumer_secret_here'

access_token_file = "token.dat"

request_token_url   = "https://%s.appspot.com/_ah/OAuthGetRequestToken" % app_id
authorize_url       = "https://%s.appspot.com/_ah/OAuthAuthorizeToken" % app_id
access_token_url    = "https://%s.appspot.com/_ah/OAuthGetAccessToken" % app_id

consumer = oauth.Consumer(consumer_key, consumer_secret)

if not os.path.exists(access_token_file):

    client = oauth.Client(consumer)

    # Step 1: Get a request token. This is a temporary token that is used for 
    # having the user authorize an access token and to sign the request to obtain 
    # said access token.

    resp, content = client.request(request_token_url, "GET")
    if resp['status'] != '200':
        raise Exception("Invalid response %s." % resp['status'])

    request_token = dict(urlparse.parse_qsl(content))

    print "Request Token:"
    print "    - oauth_token        = %s" % request_token['oauth_token']
    print "    - oauth_token_secret = %s" % request_token['oauth_token_secret']
    print 


    print "Go to the following link in your browser:"
    print "%s?oauth_token=%s" % (authorize_url, request_token['oauth_token'])
    print 

    # After the user has granted access to you, the consumer, the provider will
    # redirect you to whatever URL you have told them to redirect to. You can 
    # usually define this in the oauth_callback argument as well.
    accepted = 'n'
    while accepted.lower() == 'n':
            accepted = raw_input('Have you authorized me? (y/n) ')


    # Step 3: Once the consumer has redirected the user back to the oauth_callback
    # URL you can request the access token the user has approved. You use the 
    # request token to sign this request. After this is done you throw away the
    # request token and use the access token returned. You should store this 
    # access token somewhere safe, like a database, for future use.
    token = oauth.Token(request_token['oauth_token'],
                request_token['oauth_token_secret'])
    client = oauth.Client(consumer, token)

    resp, content = client.request(access_token_url, "POST")
    access_token = dict(urlparse.parse_qsl(content))

    print "Access Token:"
    print "    - oauth_token        = %s" % access_token['oauth_token']
    print "    - oauth_token_secret = %s" % access_token['oauth_token_secret']
    print
    print "You may now access protected resources using the access tokens above." 
    print

    token = oauth.Token(access_token['oauth_token'],
                access_token['oauth_token_secret'])

    with open(access_token_file, "w") as f:
        pickle.dump(token, f)

else:
    with open(access_token_file, "r") as f:
        token = pickle.load(f)


client = oauth.Client(consumer, token)
resp, content = client.request(url, "GET")
print "Response Status Code: %s" % resp['status']
print "Response body: %s" % content

(The basis for this script was shamelessly stolen from Joe Stump’s sample oauth2 code for his Python library on Github.)

Once we run the script using:

python oauth_client.py

we should see:

Request Token:
- oauth_token        = SOME_OAUTH_REQUEST_TOKEN_VALUE
- oauth_token_secret = SOME_OAUTH_REQUEST_SECRET_VALUE

Go to the following link in your browser:

https://YOUR-APP-ID.appspot.com/_ah/OAuthAuthorizeToken?oauth_token=SOME_OAUTH_REQUEST_TOKEN_VALUE

Have you authorized me? (y/n)

The OAuth token and token secret values are generated by the script using a combination of random values and the consumer key/secret pair. With these values, known as request tokens, you generate an authorization URL for an end user to bless our client so it can make OAuth requests on the behalf of the user that grants authorization.

At this point, the script pauses for input. As part of the OAuth dance, we need to browse to the URL provide and authorize the script. Copy/paste this URL into your browser window and click “Grant Access”:

Once we see a page that says:

You have successfully granted ikai-oauth.appspot.com access to your Google Account. You can revoke access at any time under ‘My Account’.

We can switch back to your terminal window and hit “y”. The client now exchanges our request tokens for access tokens. Access tokens are what you need to make API calls. The script outputs this:

Access Token:
- oauth_token        = SOME_OAUTH_ACCESS_TOKEN
- oauth_token_secret = SOME_OAUTH_ACCESS_TOKEN_SECRET

You may now access protected resources using the access tokens above.

Response Status Code: 200
Response body: Authenticated: the-account-you-logged-in-with@gmail.com

The Python script caches the access token in a file called token.dat, so the next time we run oauth_client.py, we skip the authorization dance and can directly make API calls:

$ python oauth_client.py
Response Status Code: 200
Response body: Authenticated:the-account-you-logged-in-with@gmail.com

That’s all there is to it!

Final notes and general tips

Setting up an OAuth provider using App Engine’s API is incredibly simple once we know all the steps. Setting up the provider is just a matter of a few lines of code, and the steps to set up the client are pretty straightforward. The most difficult part is setting up the consumer key and secret, but even that isn’t so bad once we know where the management interface is.

When possible, use OAuth instead of ClientLogin. This goes for web applications, mobile applications, desktop apps, and even command line scripts. OAuth allows users to revoke your access token and trains users not to arbitrarily give out their Google Account password to any interface that asks for it. For building clients, it also gives you a way to do client authentication without having to cache credentials – using ClientLogin too often results in CaptchaRequiredException being thrown, anyway.

– Ikai

References

Github sample code:
https://github.com/ikai/appengine-oauth-java-server-python-client-sample

App Engine/Java OAuth docs: http://code.google.com/appengine/docs/java/oauth/overview.html

Domain management – get your consumer key/secret here: https://www.google.com/accounts/ManageDomains

Python OAuth client code: https://github.com/simplegeo/python-oauth2

About these ads

Written by Ikai Lan

May 26, 2011 at 5:23 pm

25 Responses

Subscribe to comments with RSS.

  1. Great article Ikai, it makes it real simple to follow. I always like to find other guru made material on oauth. I thought I’d share a small oauth demo on GAE too here, hope you don’t mind. :)

    http://demogwtgdataoauth.appspot.com – just a quick and dirty example of oauth, with a link to its source at the top.

    Brandon Donnelson

    May 26, 2011 at 7:42 pm

  2. Hello Ikai, and really simple way to explain it. for me that I am a lover of new python.

    After your lesson you’ve made to GTUG in Palermo, I’m starting to do things in Python and App Engine. I also did a small project in http://www.comwai.com in Python and App Engine and some API Search.

    Now I will try to integrate OAuth, hopefully good :-)

    A question which editor to advise me to write python code?
    I’m also looking for something that can be used online.

    Salvino

    May 27, 2011 at 12:14 am

  3. I don’t know of any good online editors. On a Ubuntu system I use screen and VIM. On OS X I use Komodo Edit (vim is not so great on OS X).

    Ikai Lan

    May 27, 2011 at 8:57 am

  4. Hello Ikai, very good article. very simple to understand and startswith. Thanks

    George Simon

    June 1, 2011 at 1:06 am

  5. thanks for this article Ikai, but it doesn’t make me clear something. why is the provider (ikai-oauth.appspot.com) asking authorization to the user, isn’t supposed that the consumer is the one that asks for authorization?

    I want to build an API inside my app engine app and want it oauth protected (will be the provider), google accounts users have their data there. I want third party developers to create apps and mashups using my API accesing data on behalf of the google users that have accounts inside my app, so these thirdparty webapps will be oauth consumers that will need to register some how and get oauth 1.0 keys and tokens… when users use these third party apps they will have to grant access ‘to them’ no to the provider which already has their data…

    is it possible to accomplish this with the app engine oauth api?

    thanks

    damian

    Damian

    June 12, 2011 at 7:52 am

  6. I think that instead of registering the provider with google you need to register the client (the consumer), in this case, the client needs to be a webapp with a domain name. so the user will be prompted to grant authorization to ‘consumer.com’ to access ‘provider.appspot.com’. this makes sense or I am missing something?

    Damian

    June 12, 2011 at 9:18 am

  7. This seems to be outdated for Oauth2.0 dance. I am getting different screen’s and not working

    niraj

    August 17, 2011 at 3:13 pm

  8. Are you sure you are doing this on App Engine? We don’t yet support OAuth 2.0.

    http://code.google.com/appengine/docs/java/oauth/overview.html

    Ikai Lan

    August 17, 2011 at 3:21 pm

  9. Sorry got confused with all the different google websites and the confusing links. One of the google websites(http://code.google.com/apis/accounts/docs/GettingStarted.html) says that the recommended approach is to use oauth2 and I thought that the Oauthservice in appengine works with that.

    Thanks for the note.

    niraj

    August 17, 2011 at 4:21 pm

  10. Actually my specific question is – What is the best way to access Google Spreadsheets from appengine.

    The website here – http://code.google.com/apis/spreadsheets/data/3.0/developers_guide.html#ListingSpreadsheets says that oauth2 is the recommended approach.

    Is there a good sample that describes how to do the following in appengine java

    http://code.google.com/apis/accounts/docs/OAuth2.html

    niraj

    August 17, 2011 at 4:27 pm

  11. That’s unrelated to this article. You’ll want to understand the difference between an OAuth provider (what this article is about; what the GData APIs are) and writing an OAuth consumer.

    Ikai Lan

    August 20, 2011 at 4:35 pm

  12. Thanks for an excellent article. can you provide me a oauth provider application using python instead of java.???

    senthil3569

    September 18, 2011 at 11:23 pm

  13. Ikai Lan

    October 7, 2011 at 9:57 am

  14. Hi Ikai,

    Do you know whether app engine supports 2 legged or not?
    Any code example showing that?

    thanks in advance
    Fábio

    Fábio Franco Uechi

    November 7, 2011 at 8:36 pm

  15. Hi Ikai,

    I wrote this post showing a “java version” of your oauth_client.py

    http://fabiouechi.blogspot.com/2011/11/using-google-oauth-java-client-to.html

    It might be useful for other people as well.

    thanks
    Fábio

    Fábio Franco Uechi

    November 9, 2011 at 5:14 pm

  16. Thank you! This’ll be extremely useful for others.

    Ikai Lan

    November 13, 2011 at 2:47 am

  17. There’s no support for two-legged as far as I know. I’ll double check, but I’m pretty sure the answer is no. Maybe if the app is locked to a Google Apps domain … but that’d be about it.

    Ikai Lan

    November 13, 2011 at 2:48 am

  18. I was confused… please delete my two comments… I figured it out what I wanted to do, google provides everything.

    Damian

    November 16, 2011 at 12:13 pm

  19. one important issue that hasn’t been resolved since this service was fist launched.. is the fact that oauth.get_oauth_consumer_key() always raises the OAuthRequestError exception even though the OAuth authorization and Grant process is successfully..

    my concern is that GAE is on SLA , I know it is in experimental mode but It’s been a year and hasn’t been resolved… can you make an update on this issue??

    thank you

    Damian

    November 16, 2011 at 2:35 pm

  20. […] Setting up an OAuth provider on Google App Engine « Ikai Lan says […]

  21. I recently came across Fábio’s post, and was able to use it as-is in my Android client in order to authenticate with my GAE app based on python. Ikai, I was able to use your python client to do the same thing as well. However, when I modified Fábio’s code to use an HTTP Post request instead, my GAE server threw an exception when calling oauth.get_current_user(). Then I modified Ikai’s code to use a POST request instead, and it worked. Comparing the HTTP request headers and Post request payload for Fabio’s code with Ikai’s python code, I found the following difference:

    Fabio’s code using the HttpFactory.buildPostRequest() method generates an HTTP request with the oauth parameters in the HTTP headers. Ikai’s python client found on this post, converted to use a POST request puts the oauth parameters as URL encoded fields in the HTTP Post payload. Could this be the reason why my Android client using Fábio’s method + Post request does not work?

    Rishi Arora

    January 15, 2012 at 10:48 am

  22. Hi Ikai, is there a way for an oauth consumer to request access to both a google Service, e.g. Google Docs and a Google App Engine web app as scope ?? I have tried to do oauth1 authorizations and I can’t include my web service (gae app using the oauth service) and some other google services at the same time… I really need this functionality.

    thanks.
    Damian

    Damian

    January 24, 2012 at 11:17 am

  23. […] I can print it. Should I use gdocs to authenticate, or a more general client, as I is shown here : http://ikaisays.com/2011/05/26/setting-up-an-oauth-provider-on-google-app-engine/ […]

  24. […] up OAuth on AppEngine is easy – I followed this article. But the client side is a mystery, in particular I don’t know what to use for scope, in […]

  25. A very helpful article…thanks for the information!

    Ryan Brubaker

    March 22, 2013 at 7:52 pm


Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s