diff -urN -x '*.pyc' paste-1.5.1.orig/paste/auth/auth_tkt.py paste/paste/auth/auth_tkt.py
--- paste-1.5.1.orig/paste/auth/auth_tkt.py	2007-10-23 11:49:51.000000000 -0400
+++ paste/paste/auth/auth_tkt.py	2007-11-28 14:45:04.000000000 -0500
@@ -216,6 +216,17 @@
         The path under this middleware that should signify a logout.  The
         page will be shown as usual, but the user will also be logged out
         when they visit this page.
+
+    ``timeout``:
+        How many seconds before the cookie is considered invalid.  Default
+        is None (never timeout)
+
+    ``refresh``:
+        A number between 0 and 1 representing the number of seconds (as
+        a fraction of ``timeout``) after which a valid cookie is refreshed.
+        Set to 0 to never refresh (the default)
+        Set to 1 to always refresh
+        Set to 0.33 to refresh the cookie after 0.33 * ``timeout`` seconds
         
     If used with mod_auth_tkt, then these settings (except logout_path) should 
     match the analogous Apache configuration settings.
@@ -234,20 +245,40 @@
     """
 
     def __init__(self, app, secret, cookie_name='auth_tkt', secure=False,
-                 include_ip=True, logout_path=None):
+                 include_ip=True, logout_path=None, timeout=None,
+                 refresh=0):
         self.app = app
         self.secret = secret
         self.cookie_name = cookie_name
         self.secure = secure
         self.include_ip = include_ip
         self.logout_path = logout_path
+        self.timeout = timeout
+        self.refresh = float(refresh)
 
     def __call__(self, environ, start_response):
+        set_cookies = []
+        def set_user(userid, tokens='', user_data=''):
+            set_cookies.extend(self.set_user_cookie(
+                environ, userid, tokens, user_data))
+        def logout_user():
+            set_cookies.extend(self.logout_user_cookie(environ))
+        environ['paste.auth_tkt.set_user'] = set_user
+        environ['paste.auth_tkt.logout_user'] = logout_user
+
+        def cookie_setting_start_response(status, headers, exc_info=None):
+            headers.extend(set_cookies)
+            return start_response(status, headers, exc_info)
+
         cookies = request.get_cookies(environ)
         if cookies.has_key(self.cookie_name):
             cookie_value = cookies[self.cookie_name].value
         else:
             cookie_value = ''
+
+        if self.logout_path and environ.get('PATH_INFO') == self.logout_path:
+            logout_user()
+
         if cookie_value:
             if self.include_ip:
                 remote_addr = environ['REMOTE_ADDR']
@@ -256,30 +287,28 @@
                 # checked:
                 remote_addr = '0.0.0.0'
             # @@: This should handle bad signatures better:
-            # Also, timeouts should cause cookie refresh
             timestamp, userid, tokens, user_data = parse_ticket(
                 self.secret, cookie_value, remote_addr)
-            tokens = ','.join(tokens)
-            environ['REMOTE_USER'] = userid
-            if environ.get('REMOTE_USER_TOKENS'):
-                # We want to add tokens/roles to what's there:
-                tokens = environ['REMOTE_USER_TOKENS'] + ',' + tokens
-            environ['REMOTE_USER_TOKENS'] = tokens
-            environ['REMOTE_USER_DATA'] = user_data
-            environ['AUTH_TYPE'] = 'cookie'
-        set_cookies = []
-        def set_user(userid, tokens='', user_data=''):
-            set_cookies.extend(self.set_user_cookie(
-                environ, userid, tokens, user_data))
-        def logout_user():
-            set_cookies.extend(self.logout_user_cookie(environ))
-        environ['paste.auth_tkt.set_user'] = set_user
-        environ['paste.auth_tkt.logout_user'] = logout_user
-        if self.logout_path and environ.get('PATH_INFO') == self.logout_path:
-            logout_user()
-        def cookie_setting_start_response(status, headers, exc_info=None):
-            headers.extend(set_cookies)
-            return start_response(status, headers, exc_info)
+            # Check the timestamp
+            now = time_mod.time()
+            if self.timeout is None or timestamp + self.timeout > now:
+                cookieTokens = ','.join(tokens)
+                environ['REMOTE_USER'] = userid
+                if environ.get('REMOTE_USER_TOKENS'):
+                    # We want to add tokens/roles to what's there:
+                    tokens = environ['REMOTE_USER_TOKENS'] + ',' + cookieTokens
+                environ['REMOTE_USER_TOKENS'] = tokens
+                environ['REMOTE_USER_DATA'] = user_data
+                environ['AUTH_TYPE'] = 'cookie'
+                # Refresh the cookie if necessary
+                if self.timeout is not None:
+                    elapsed = now - timestamp
+                    if elapsed > (self.refresh * self.timeout):
+                        set_user(userid, cookieTokens, user_data)
+            else:
+                # The cookie expired
+                pass
+
         return self.app(environ, cookie_setting_start_response)
 
     def set_user_cookie(self, environ, userid, tokens, user_data):
@@ -323,7 +352,9 @@
     cookie_name='auth_tkt',
     secure=False,
     include_ip=True,
-    logout_path=None):
+    logout_path=None,
+    timeout=None,
+    refresh=0):
     """
     Creates the `AuthTKTMiddleware
     <class-paste.auth.auth_tkt.AuthTKTMiddleware.html>`_.
@@ -339,4 +370,5 @@
         raise ValueError(
             "You must provide a 'secret' (in global or local configuration)")
     return AuthTKTMiddleware(
-        app, secret, cookie_name, secure, include_ip, logout_path or None)
+        app, secret, cookie_name, secure, include_ip, logout_path or None,
+        timeout, refresh)
diff -urN -x '*.pyc' paste-1.5.1.orig/tests/test_auth/test_auth_tkt.py paste/tests/test_auth/test_auth_tkt.py
--- paste-1.5.1.orig/tests/test_auth/test_auth_tkt.py	1969-12-31 19:00:00.000000000 -0500
+++ paste/tests/test_auth/test_auth_tkt.py	2007-11-28 14:29:51.000000000 -0500
@@ -0,0 +1,129 @@
+# (c) 2007 Chris AtLee
+# This module is part of the Python Paste Project and is released under
+# the MIT License: http://www.opensource.org/licenses/mit-license.php
+
+from paste.auth.auth_tkt import *
+from paste.wsgilib import raw_interactive, dump_environ
+from paste.response import header_value
+from paste.httpexceptions import *
+import os
+
+import py.test
+import time as time_mod
+
+secret = "s3krit"
+
+def test_noop():
+    app = AuthTKTMiddleware(dump_environ, secret)
+
+    (status, headers, content, errors) = \
+            raw_interactive(app)
+
+    value = header_value(headers, 'Set-Cookie')
+    assert value is None
+
+def test_basic():
+    app = AuthTKTMiddleware(dump_environ, secret)
+
+    tkt = AuthTicket(secret, 'catlee', '0.0.0.0')
+
+    cookie = "%s=%s" % ("auth_tkt", tkt.cookie_value())
+
+    (status, headers, content, errors) = \
+            raw_interactive(app, HTTP_COOKIE=cookie, REMOTE_ADDR="0.0.0.0")
+
+    assert "REMOTE_USER: catlee" in content
+
+def test_ipcheck():
+    app = AuthTKTMiddleware(dump_environ, secret)
+
+    tkt = AuthTicket(secret, 'catlee', '0.0.0.1')
+
+    cookie = "%s=%s" % ("auth_tkt", tkt.cookie_value())
+
+    py.test.raises(BadTicket,
+            raw_interactive, app, HTTP_COOKIE=cookie, REMOTE_ADDR="0.0.0.0")
+
+def test_cookiename():
+    app = AuthTKTMiddleware(dump_environ, secret, cookie_name = "secret")
+
+    tkt = AuthTicket(secret, 'catlee', '0.0.0.0')
+
+    cookie = "%s=%s" % ("secret", tkt.cookie_value())
+
+    (status, headers, content, errors) = \
+            raw_interactive(app, HTTP_COOKIE=cookie, REMOTE_ADDR="0.0.0.0")
+
+    assert "REMOTE_USER: catlee" in content
+
+def test_logout():
+    app = AuthTKTMiddleware(dump_environ, secret, logout_path="/logout")
+
+    (status, headers, content, errors) = \
+            raw_interactive(app, "/logout")
+
+    value = header_value(headers, 'Set-Cookie')
+    assert value is not None
+
+def test_nologout():
+    app = AuthTKTMiddleware(dump_environ, secret, logout_path="/logout")
+
+    (status, headers, content, errors) = \
+            raw_interactive(app, "/dontlogout")
+
+    value = header_value(headers, 'Set-Cookie')
+    assert value is None
+
+def test_notimeout():
+    app = AuthTKTMiddleware(dump_environ, secret, timeout=60)
+
+    now = time_mod.time()
+
+    tkt = AuthTicket(secret, 'catlee', '0.0.0.0', time=now)
+    cookie = "%s=%s" % ("auth_tkt", tkt.cookie_value())
+
+    (status, headers, content, errors) = \
+            raw_interactive(app, HTTP_COOKIE=cookie, REMOTE_ADDR="0.0.0.0")
+
+    assert "REMOTE_USER: catlee" in content
+
+def test_timeout():
+    app = AuthTKTMiddleware(dump_environ, secret, timeout=60)
+
+    now = time_mod.time()
+
+    tkt = AuthTicket(secret, 'catlee', '0.0.0.0', time=now-120)
+    cookie = "%s=%s" % ("auth_tkt", tkt.cookie_value())
+
+    (status, headers, content, errors) = \
+            raw_interactive(app, HTTP_COOKIE=cookie, REMOTE_ADDR="0.0.0.0")
+
+    assert "REMOTE_USER: catlee" not in content
+
+def test_refresh():
+    app = AuthTKTMiddleware(dump_environ, secret, timeout=60, refresh=0.5)
+
+    now = time_mod.time()
+
+    tkt = AuthTicket(secret, 'catlee', '0.0.0.0', time=now-40)
+    cookie = "%s=%s" % ("auth_tkt", tkt.cookie_value())
+
+    (status, headers, content, errors) = \
+            raw_interactive(app, HTTP_COOKIE=cookie, REMOTE_ADDR="0.0.0.0")
+
+    value = header_value(headers, 'Set-Cookie')
+    assert value is not None
+
+def test_norefresh():
+    app = AuthTKTMiddleware(dump_environ, secret, timeout=60, refresh=0.5)
+
+    now = time_mod.time()
+
+    tkt = AuthTicket(secret, 'catlee', '0.0.0.0', time=now-20)
+    cookie = "%s=%s" % ("auth_tkt", tkt.cookie_value())
+
+    (status, headers, content, errors) = \
+            raw_interactive(app, HTTP_COOKIE=cookie, REMOTE_ADDR="0.0.0.0")
+
+    value = header_value(headers, 'Set-Cookie')
+    assert value is None

