Moving over OAuth 1.0 to use Storage, and updating samples to handle token revocation.
diff --git a/apiclient/ext/file.py b/apiclient/ext/file.py
index 052a91b..be72497 100644
--- a/apiclient/ext/file.py
+++ b/apiclient/ext/file.py
@@ -10,8 +10,10 @@
 
 import pickle
 
+from apiclient.oauth import Storage as BaseStorage
 
-class Storage(object):
+
+class Storage(BaseStorage):
   """Store and retrieve a single credential to and from a file."""
 
   def __init__(self, filename):
@@ -29,6 +31,7 @@
       f.close()
     except:
       credentials = None
+    credentials.set_store(self.put)
 
     return credentials
 
diff --git a/apiclient/oauth.py b/apiclient/oauth.py
index 1cc6cef..aacdaef 100644
--- a/apiclient/oauth.py
+++ b/apiclient/oauth.py
@@ -7,13 +7,13 @@
 
 __author__ = 'jcgregorio@google.com (Joe Gregorio)'
 
+
 import copy
 import httplib2
 import logging
 import oauth2 as oauth
 import urllib
 import urlparse
-
 from anyjson import simplejson
 
 try:
@@ -36,6 +36,10 @@
   pass
 
 
+class CredentialsInvalidError(Error):
+  pass
+
+
 def _abstract():
   raise NotImplementedError('You need to override this function')
 
@@ -84,6 +88,29 @@
   pass
 
 
+class Storage(object):
+  """Base class for all Storage objects.
+
+  Store and retrieve a single credential.
+  """
+
+  def get(self):
+    """Retrieve credential.
+
+    Returns:
+      apiclient.oauth.Credentials
+    """
+    _abstract()
+
+  def put(self, credentials):
+    """Write a credential.
+
+    Args:
+      credentials: Credentials, the credentials to store.
+    """
+    _abstract()
+
+
 class OAuthCredentials(Credentials):
   """Credentials object for OAuth 1.0a
   """
@@ -98,6 +125,39 @@
     self.consumer = consumer
     self.token = token
     self.user_agent = user_agent
+    self.store = None
+
+    # True if the credentials have been revoked
+    self._invalid = False
+
+  @property
+  def invalid(self):
+    """True if the credentials are invalid, such as being revoked."""
+    return getattr(self, "_invalid", False)
+
+  def set_store(self, store):
+    """Set the storage for the credential.
+
+    Args:
+      store: callable, a callable that when passed a Credential
+        will store the credential back to where it came from.
+        This is needed to store the latest access_token if it
+        has been revoked.
+    """
+    self.store = store
+
+  def __getstate__(self):
+    """Trim the state down to something that can be pickled.
+    """
+    d = copy.copy(self.__dict__)
+    del d['store']
+    return d
+
+  def __setstate__(self, state):
+    """Reconstitute the state of the object from being pickled.
+    """
+    self.__dict__.update(state)
+    self.store = None
 
   def authorize(self, http):
     """
@@ -148,6 +208,15 @@
         response_code = resp.status
         if response_code in [301, 302]:
           uri = resp['location']
+
+      # Update the stored credential if it becomes invalid.
+      if response_code == 401:
+        logging.info('Access token no longer valid: %s' % content)
+        self._invalid = True
+        if self.store is not None:
+          self.store(self)
+        raise CredentialsInvalidError("Credentials are no longer valid.")
+
       return resp, content
 
     http.request = new_request
diff --git a/oauth2client/client.py b/oauth2client/client.py
index 3527a48..e972564 100644
--- a/oauth2client/client.py
+++ b/oauth2client/client.py
@@ -208,7 +208,8 @@
         d = simplejson.loads(content)
         if 'error' in d:
           self._invalid = True
-          self.store(self)
+          if self.store is not None:
+            self.store(self)
       except:
         pass
       logging.error('Failed to retrieve access token: %s' % content)
diff --git a/samples/buzz/buzz.py b/samples/buzz/buzz.py
index a4f6840..cf3581b 100644
--- a/samples/buzz/buzz.py
+++ b/samples/buzz/buzz.py
@@ -14,7 +14,8 @@
 from apiclient.discovery import build
 from apiclient.oauth import FlowThreeLegged
 from apiclient.ext.authtools import run
-
+from apiclient.ext.file import Storage
+from apiclient.oauth import CredentialsInvalidError
 
 import httplib2
 import pickle
@@ -25,11 +26,8 @@
 
 
 def main():
-  try:
-    f = open("buzz.dat", "r")
-    credentials = pickle.loads(f.read())
-    f.close()
-  except:
+  credentials = Storage('buzz.dat').get()
+  if credentials is None or credentials.invalid == True:
     buzz_discovery = build("buzz", "v1").auth_discovery()
 
     flow = FlowThreeLegged(buzz_discovery,
@@ -49,43 +47,49 @@
       developerKey="AIzaSyDRRpR3GS1F1_jKNNM9HCNd2wJQyPG3oN0")
   activities = p.activities()
 
-  # Retrieve the first two activities
-  activitylist = activities.list(
-      max_results='2', scope='@self', userId='@me').execute()
-  print "Retrieved the first two activities"
+  try:
+    # Retrieve the first two activities
+    activitylist = activities.list(
+        max_results='2', scope='@self', userId='@me').execute()
+    print "Retrieved the first two activities"
 
-  # Retrieve the next two activities
-  if activitylist:
-    activitylist = activities.list_next(activitylist).execute()
-    print "Retrieved the next two activities"
+    # Retrieve the next two activities
+    if activitylist:
+      activitylist = activities.list_next(activitylist).execute()
+      print "Retrieved the next two activities"
 
-  # Add a new activity
-  new_activity_body = {
-      "data": {
-        'title': 'Testing insert',
-        'object': {
-          'content': u'Just a short note to show that insert is working. ☄',
-          'type': 'note'}
-        }
-      }
-  activity = activities.insert(userId='@me', body=new_activity_body).execute()
-  print "Added a new activity"
-
-  activitylist = activities.list(
-      max_results='2', scope='@self', userId='@me').execute()
-
-  # Add a comment to that activity
-  comment_body = {
-      "data": {
-          "content": "This is a comment"
+    # Add a new activity
+    new_activity_body = {
+        "data": {
+          'title': 'Testing insert',
+          'object': {
+            'content':
+              u'Just a short note to show that insert is working. ☄',
+            'type': 'note'}
           }
-      }
-  item = activitylist['items'][0]
-  comment = p.comments().insert(
-      userId=item['actor']['id'], postId=item['id'], body=comment_body
-      ).execute()
-  print 'Added a comment to the new activity'
-  pprint.pprint(comment)
+        }
+    activity = activities.insert(
+        userId='@me', body=new_activity_body).execute()
+    print "Added a new activity"
+
+    activitylist = activities.list(
+        max_results='2', scope='@self', userId='@me').execute()
+
+    # Add a comment to that activity
+    comment_body = {
+        "data": {
+            "content": "This is a comment"
+            }
+        }
+    item = activitylist['items'][0]
+    comment = p.comments().insert(
+        userId=item['actor']['id'], postId=item['id'], body=comment_body
+        ).execute()
+    print 'Added a comment to the new activity'
+    pprint.pprint(comment)
+  except CredentialsInvalidError:
+    print 'Your credentials are no longer valid.'
+    print 'Please re-run this application to re-authorize.'
 
 if __name__ == '__main__':
   main()
diff --git a/samples/latitude/latitude.py b/samples/latitude/latitude.py
index 1dd1c39..c2ec635 100644
--- a/samples/latitude/latitude.py
+++ b/samples/latitude/latitude.py
@@ -28,7 +28,7 @@
 
 def main():
   credentials = Storage('latitude.dat').get()
-  if credentials is None:
+  if credentials is None or credentials.invalid == True:
     auth_discovery = build("latitude", "v1").auth_discovery()
     flow = FlowThreeLegged(auth_discovery,
                            # You MUST have a consumer key and secret tied to a
diff --git a/samples/oauth2/latitude/latitude.py b/samples/oauth2/latitude/latitude.py
index e0458f4..56df083 100644
--- a/samples/oauth2/latitude/latitude.py
+++ b/samples/oauth2/latitude/latitude.py
@@ -17,15 +17,14 @@
 from oauth2client.file import Storage
 from oauth2client.client import OAuth2WebServerFlow
 from oauth2client.tools import run
+from apiclient.oauth import CredentialsInvalidError
 
 # Uncomment to get detailed logging
 #httplib2.debuglevel = 4
 
 
 def main():
-  storage = Storage('latitude.dat')
-  credentials = storage.get()
-
+  credentials = Storage('latitude.dat').get()
   if credentials is None or credentials.invalid:
     flow = OAuth2WebServerFlow(
         client_id='433807057907.apps.googleusercontent.com',
@@ -50,7 +49,11 @@
           "altitude": 35
           }
       }
-  print p.currentLocation().insert(body=body).execute()
+  try:
+    print p.currentLocation().insert(body=body).execute()
+  except CredentialsInvalidError:
+    print 'Your credentials are no longer valid.'
+    print 'Please re-run this application to re-authorize.'
 
 if __name__ == '__main__':
   main()