Add robot helpers and a sample.
diff --git a/oauth2client/appengine.py b/oauth2client/appengine.py
index 71aa8f0..a9766c7 100644
--- a/oauth2client/appengine.py
+++ b/oauth2client/appengine.py
@@ -21,14 +21,29 @@
 
 import httplib2
 import pickle
+import time
+import base64
+import logging
+
+try: # pragma: no cover
+  import simplejson
+except ImportError: # pragma: no cover
+  try:
+    # Try to import from django, should work on App Engine
+    from django.utils import simplejson
+  except ImportError:
+    # Should work for Python2.6 and higher.
+    import json as simplejson
 
 from client import AccessTokenRefreshError
+from client import AssertionCredentials
 from client import Credentials
 from client import Flow
 from client import OAuth2WebServerFlow
 from client import Storage
 from google.appengine.api import memcache
 from google.appengine.api import users
+from google.appengine.api.app_identity import app_identity
 from google.appengine.ext import db
 from google.appengine.ext import webapp
 from google.appengine.ext.webapp.util import login_required
@@ -36,6 +51,76 @@
 
 OAUTH2CLIENT_NAMESPACE = 'oauth2client#ns'
 
+
+class AppAssertionCredentials(AssertionCredentials):
+  """Credentials object for App Engine Assertion Grants
+
+  This object will allow an App Engine application to identify itself to Google
+  and other OAuth 2.0 servers that can verify assertions. It can be used for
+  the purpose of accessing data stored under an account assigned to the App
+  Engine application itself. The algorithm used for generating the assertion is
+  the Signed JSON Web Token (JWT) algorithm. Additional details can be found at
+  the following link:
+
+  http://self-issued.info/docs/draft-jones-json-web-token.html
+
+  This credential does not require a flow to instantiate because it represents
+  a two legged flow, and therefore has all of the required information to
+  generate and refresh its own access tokens.
+
+  AssertionFlowCredentials objects may be safely pickled and unpickled.
+  """
+
+  def __init__(self, scope, user_agent,
+      audience='https://accounts.google.com/o/oauth2/token',
+      assertion_type='http://oauth.net/grant_type/jwt/1.0/bearer',
+      token_uri='https://accounts.google.com/o/oauth2/token', **kwargs):
+    """Constructor for AppAssertionCredentials
+
+    Args:
+      scope: string, scope of the credentials being requested.
+      user_agent: string, The HTTP User-Agent to provide for this application.
+      audience: string, The audience, or verifier of the assertion.  For
+        convenience defaults to Google's audience.
+      assertion_type: string, Type name that will identify the format of the
+        assertion string.  For convience, defaults to the JSON Web Token (JWT)
+        assertion type string.
+      token_uri: string, URI for token endpoint. For convenience
+        defaults to Google's endpoints but any OAuth 2.0 provider can be used.
+    """
+    self.scope = scope
+    self.audience = audience
+    self.app_name = app_identity.get_service_account_name()
+
+    super(AppAssertionCredentials, self).__init__(
+        assertion_type,
+        user_agent,
+        token_uri)
+
+  def _generate_assertion(self):
+    header = {
+      'typ': 'JWT',
+      'alg': 'RS256',
+    }
+
+    now = int(time.time())
+    claims = {
+      'aud': self.audience,
+      'scope': self.scope,
+      'iat': now,
+      'exp': now + 3600,
+      'iss': self.app_name,
+    }
+
+    jwt_components = [base64.b64encode(simplejson.dumps(seg))
+        for seg in [header, claims]]
+
+    base_str = ".".join(jwt_components)
+    key_name, signature = app_identity.sign_blob(base_str)
+    jwt_components.append(base64.b64encode(signature))
+    return ".".join(jwt_components)
+
+
 class FlowProperty(db.Property):
   """App Engine datastore Property for Flow.
 
@@ -117,7 +202,7 @@
     Args:
       model: db.Model, model class
       key_name: string, key name for the entity that has the credentials
-      property_name: string, name of the property that is an CredentialsProperty
+      property_name: string, name of the property that is a CredentialsProperty
       cache: memcache, a write-through cache to put in front of the datastore
     """
     self._model = model
@@ -189,6 +274,7 @@
         # in API calls
 
   """
+
   def __init__(self, client_id, client_secret, scope, user_agent,
                auth_uri='https://accounts.google.com/o/oauth2/auth',
                token_uri='https://accounts.google.com/o/oauth2/token'):
@@ -205,8 +291,8 @@
       token_uri: string, URI for token endpoint. For convenience
         defaults to Google's endpoints but any OAuth 2.0 provider can be used.
     """
-    self.flow = OAuth2WebServerFlow(client_id, client_secret, scope, user_agent,
-      auth_uri, token_uri)
+    self.flow = OAuth2WebServerFlow(client_id, client_secret, scope,
+      user_agent, auth_uri, token_uri)
     self.credentials = None
     self._request_handler = None
 
@@ -220,6 +306,7 @@
       method: callable, to be decorated method of a webapp.RequestHandler
         instance.
     """
+
     def check_oauth(request_handler, *args):
       user = users.get_current_user()
       # Don't use @login_decorator as this could be used in a POST request.
@@ -255,6 +342,7 @@
       method: callable, to be decorated method of a webapp.RequestHandler
         instance.
     """
+
     def setup_oauth(request_handler, *args):
       user = users.get_current_user()
       # Don't use @login_decorator as this could be used in a POST request.
@@ -308,10 +396,12 @@
     error = self.request.get('error')
     if error:
       errormsg = self.request.get('error_description', error)
-      self.response.out.write('The authorization request failed: %s' % errormsg)
+      self.response.out.write(
+          'The authorization request failed: %s' % errormsg)
     else:
       user = users.get_current_user()
-      flow = pickle.loads(memcache.get(user.user_id(), namespace=OAUTH2CLIENT_NAMESPACE))
+      flow = pickle.loads(memcache.get(user.user_id(),
+                                       namespace=OAUTH2CLIENT_NAMESPACE))
       # This code should be ammended with application specific error
       # handling. The following cases should be considered:
       # 1. What if the flow doesn't exist in memcache? Or is corrupt?
@@ -328,6 +418,7 @@
 
 application = webapp.WSGIApplication([('/oauth2callback', OAuth2Handler)])
 
+
 def main():
   run_wsgi_app(application)