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