diff --git a/CHANGELOG.md b/CHANGELOG.md
index f15bc9e..b5fcbb5 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -13,6 +13,7 @@ Improvements:
   - Move WSGI server code into its own module ([@wndhydrnt][])
   - Renamed class acting as entrypoint for WSGI server from 'Server' to 'Application' ([@wndhydrnt][])
   - Client Credentials Grant example ([@shupp][])
+  - Methods `authenticate` and `render_auth_page` of a Site Adapter accept an instance of `oauth2.datatype.Client` ([@wndhydrnt][])
 
 Bugfixes:
 
diff --git a/README.rst b/README.rst
index 0b77e9b..a745d83 100644
--- a/README.rst
+++ b/README.rst
@@ -42,14 +42,15 @@ Example Authorization server
     # This can be used to display confirmation dialogs and the like.
     class ExampleSiteAdapter(oauth2.web.AuthorizationCodeGrantSiteAdapter,
                              oauth2.web.ImplicitGrantSiteAdapter):
-        def authenticate(self, request, environ, scopes):
+        def authenticate(self, request, environ, scopes, client):
             # Check if the user has granted access
             if request.post_param("confirm") == "confirm":
                 return {}
 
             raise oauth2.error.UserNotAuthenticated
 
-        def render_auth_page(self, request, response, environ, scopes):
+        def render_auth_page(self, request, response, environ, scopes,
+                             client):
             response.body = '''
     <html>
         <body>
diff --git a/docs/examples/authorization_code_grant.py b/docs/examples/authorization_code_grant.py
index a8ecf82..ff82b4c 100644
--- a/docs/examples/authorization_code_grant.py
+++ b/docs/examples/authorization_code_grant.py
@@ -68,12 +68,12 @@ class TestSiteAdapter(AuthorizationCodeGrantSiteAdapter):
 </html>
     """
 
-    def render_auth_page(self, request, response, environ, scopes):
+    def render_auth_page(self, request, response, environ, scopes, client):
         response.body = self.CONFIRMATION_TEMPLATE
 
         return response
 
-    def authenticate(self, request, environ, scopes):
+    def authenticate(self, request, environ, scopes, client):
         if request.method == "POST":
             if request.post_param("confirm") == "1":
                 return
diff --git a/docs/examples/base_server.py b/docs/examples/base_server.py
index be43cb5..27ac9b1 100644
--- a/docs/examples/base_server.py
+++ b/docs/examples/base_server.py
@@ -11,14 +11,14 @@ import oauth2.web.wsgi
 # This can be used to display confirmation dialogs and the like.
 class ExampleSiteAdapter(oauth2.web.AuthorizationCodeGrantSiteAdapter,
                          oauth2.web.ImplicitGrantSiteAdapter):
-    def authenticate(self, request, environ, scopes):
+    def authenticate(self, request, environ, scopes, client):
         # Check if the user has granted access
         if request.post_param("confirm") == "confirm":
             return {}
 
         raise oauth2.error.UserNotAuthenticated
 
-    def render_auth_page(self, request, response, environ, scopes):
+    def render_auth_page(self, request, response, environ, scopes, client):
         response.body = '''
 <html>
     <body>
diff --git a/docs/examples/implicit_grant.py b/docs/examples/implicit_grant.py
index 4368f98..0d244d3 100644
--- a/docs/examples/implicit_grant.py
+++ b/docs/examples/implicit_grant.py
@@ -40,13 +40,13 @@ class TestSiteAdapter(ImplicitGrantSiteAdapter):
 </html>
     """
 
-    def render_auth_page(self, request, response, environ, scopes):
+    def render_auth_page(self, request, response, environ, scopes, client):
         # Add check if the user is logged or a redirect to the login page here
         response.body = self.CONFIRMATION_TEMPLATE
 
         return response
 
-    def authenticate(self, request, environ, scopes):
+    def authenticate(self, request, environ, scopes, client):
         if request.method == "POST":
             if request.post_param("confirm") == "1":
                 return
diff --git a/docs/examples/resource_owner_grant.py b/docs/examples/resource_owner_grant.py
index 16d7990..d539ee6 100644
--- a/docs/examples/resource_owner_grant.py
+++ b/docs/examples/resource_owner_grant.py
@@ -157,7 +157,7 @@ class ClientApplication(object):
 
 
 class TestSiteAdapter(ResourceOwnerGrantSiteAdapter):
-    def authenticate(self, request, environ, scopes):
+    def authenticate(self, request, environ, scopes, client):
         username = request.post_param("username")
         password = request.post_param("password")
         # A real world application could connect to a database, try to
diff --git a/docs/examples/tornado_server.py b/docs/examples/tornado_server.py
index 869be94..f9a77b6 100644
--- a/docs/examples/tornado_server.py
+++ b/docs/examples/tornado_server.py
@@ -70,12 +70,12 @@ class TestSiteAdapter(AuthorizationCodeGrantSiteAdapter):
 </html>
     """
 
-    def render_auth_page(self, request, response, environ, scopes):
+    def render_auth_page(self, request, response, environ, scopes, client):
         response.body = self.CONFIRMATION_TEMPLATE
 
         return response
 
-    def authenticate(self, request, environ, scopes):
+    def authenticate(self, request, environ, scopes, client):
         if request.method == "POST":
             if request.post_param("confirm") == "1":
                 return
diff --git a/docs/migration.rst b/docs/migration.rst
index 218db95..c4ccf14 100644
--- a/docs/migration.rst
+++ b/docs/migration.rst
@@ -83,3 +83,32 @@ After:
     # Instantiating storage and provider...
 
     app = Application(provider=provider)
+
+
+Client passed to methods authenticate and render_auth_page of a Site Adapter
+^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+Before:
+
+.. code-block:: python
+
+    class ExampleSiteAdapter(AuthenticatingSiteAdapter, UserFacingSiteAdapter):
+        def authenticate(self, request, environ, scopes):
+            # code
+
+        def render_auth_page(self, request, response, environ, scopes):
+            # code
+
+
+After:
+
+.. code-block:: python
+
+    class ExampleSiteAdapter(AuthenticatingSiteAdapter, UserFacingSiteAdapter):
+        def authenticate(self, request, environ, scopes, client):
+            # code
+
+        def render_auth_page(self, request, response, environ, scopes, client):
+            # code
+
+
diff --git a/oauth2/grant.py b/oauth2/grant.py
index a792edd..1407af0 100644
--- a/oauth2/grant.py
+++ b/oauth2/grant.py
@@ -306,12 +306,14 @@ class AuthorizeMixin(object):
                                     explanation="Authorization denied by user")
 
         try:
-            result = self.site_adapter.authenticate(request, environ, scopes)
+            result = self.site_adapter.authenticate(request, environ, scopes,
+                                                    self.client)
 
             return self.sanitize_return_value(result)
         except UserNotAuthenticated:
             return self.site_adapter.render_auth_page(request, response,
-                                                      environ, scopes)
+                                                      environ, scopes,
+                                                      self.client)
 
     @staticmethod
     def sanitize_return_value(value):
@@ -816,7 +818,8 @@ class ResourceOwnerGrantHandler(GrantHandler, AccessTokenMixin):
         """
         try:
             data = self.site_adapter.authenticate(request, environ,
-                                                  self.scope_handler.scopes)
+                                                  self.scope_handler.scopes,
+                                                  self.client)
             data = AuthorizeMixin.sanitize_return_value(data)
         except UserNotAuthenticated:
             raise OAuthInvalidError(error="invalid_client",
diff --git a/oauth2/web/__init__.py b/oauth2/web/__init__.py
index 279692e..4e98019 100644
--- a/oauth2/web/__init__.py
+++ b/oauth2/web/__init__.py
@@ -6,7 +6,7 @@ class AuthenticatingSiteAdapter(object):
     """
     Extended by site adapters that need to authenticate the user.
     """
-    def authenticate(self, request, environ, scopes):
+    def authenticate(self, request, environ, scopes, client):
         """
         Authenticates a user and checks if she has authorized access.
 
@@ -20,6 +20,9 @@ class AuthenticatingSiteAdapter(object):
                        scope.
         :type scopes: list
 
+        :param client: The client that initiated the authorization process
+        :type client: oauth2.datatype.Client
+
         :return: A ``dict`` containing arbitrary data that will be passed to
                  the current storage adapter and saved with auth code and
                  access token. Return a tuple in the form
@@ -40,7 +43,7 @@ class UserFacingSiteAdapter(object):
     Display HTML or redirect the user agent to another page of your website
     where she can do something before being returned to the OAuth 2.0 server.
     """
-    def render_auth_page(self, request, response, environ, scopes):
+    def render_auth_page(self, request, response, environ, scopes, client):
         """
         Defines how to display a confirmation page to the user.
 
@@ -57,6 +60,9 @@ class UserFacingSiteAdapter(object):
                        scope.
         :type scopes: list
 
+        :param client: The client that initiated the authorization process
+        :type client: oauth2.datatype.Client
+
         :return: The response passed in as a parameter.
                  It can contain HTML or issue a redirect.
         :rtype: oauth2.web.Response
diff --git a/setup.py b/setup.py
index f026e85..4200b67 100644
--- a/setup.py
+++ b/setup.py
@@ -1,3 +1,4 @@
+import os
 import sys
 
 from setuptools import setup
@@ -15,8 +16,7 @@ setup(name="python-oauth2",
       author="Markus Meyer",
       author_email="hydrantanderwand@gmail.com",
       url="https://github.com/wndhydrnt/python-oauth2",
-      packages=["oauth2", "oauth2.web", "oauth2.store", "oauth2.store.dbapi",
-                "oauth2.test"],
+      packages=[d[0].replace("/", ".") for d in os.walk("oauth2") if not d[0].endswith("__pycache__")],
       extras_require={
         "memcache": [memcache_require],
         "mongodb": ["pymongo"],

New parameter client 
**AuthenticatingSiteAdapter.authenticate** and **UserFacingSiteAdapter.render_auth_page** could have a parameter to receive the client retrieved from the store.

In my case, my client table has extra columns that I need to render the authentication page, If I had access to the client object it would be easier. 

Thanks!
diff --git a/oauth2/test/functional/test_authorization_code.py b/oauth2/test/functional/test_authorization_code.py
index 6706ad2..bd2ef3a 100644
--- a/oauth2/test/functional/test_authorization_code.py
+++ b/oauth2/test/functional/test_authorization_code.py
@@ -203,7 +203,7 @@ class AuthorizationCodeTestCase(unittest.TestCase):
 
 
 class TestSiteAdapter(AuthorizationCodeGrantSiteAdapter):
-    def authenticate(self, request, environ, scopes):
+    def authenticate(self, request, environ, scopes, client):
         return {"additional": "data"}, 1
 
     def user_has_denied_access(self, request):
diff --git a/oauth2/test/test_grant.py b/oauth2/test/test_grant.py
index e3f80b8..cfbb05b 100644
--- a/oauth2/test/test_grant.py
+++ b/oauth2/test/test_grant.py
@@ -149,6 +149,8 @@ class AuthorizeMixinTestCase(unittest.TestCase):
         """
         AuthorizeMixin.authorize should return a tuple even if the SiteAdapter returns a dict
         """
+        client_mock = Mock(spec=Client)
+
         test_data = {"test": "data"}
 
         site_adapter_mock = Mock(spec=ImplicitGrantSiteAdapter)
@@ -156,6 +158,7 @@ class AuthorizeMixinTestCase(unittest.TestCase):
         site_adapter_mock.authenticate.return_value = test_data
 
         auth_mixin = AuthorizeMixin(site_adapter=site_adapter_mock)
+        auth_mixin.client = client_mock
         result = auth_mixin.authorize(Mock(spec=Request), Mock(spec=Response),
                                       environ={}, scopes=[])
 
@@ -167,6 +170,8 @@ class AuthorizeMixinTestCase(unittest.TestCase):
         """
         AuthorizeMixin.authorize should return the tuple returned by the SiteAdapter
         """
+        client_mock = Mock(spec=Client)
+
         test_data = ({"test": "data"}, 123)
 
         site_adapter_mock = Mock(spec=ImplicitGrantSiteAdapter)
@@ -174,6 +179,7 @@ class AuthorizeMixinTestCase(unittest.TestCase):
         site_adapter_mock.authenticate.return_value = test_data
 
         auth_mixin = AuthorizeMixin(site_adapter=site_adapter_mock)
+        auth_mixin.client = client_mock
         result = auth_mixin.authorize(Mock(spec=Request), Mock(spec=Response),
                                       environ={}, scopes=[])
 
@@ -182,6 +188,8 @@ class AuthorizeMixinTestCase(unittest.TestCase):
         self.assertEqual(result[1], test_data[1])
 
     def test_authorize_user_not_authenticated(self):
+        client_mock = Mock(spec=Client)
+
         response_mock = Mock(spec=Response)
 
         site_adapter_mock = Mock(spec=ImplicitGrantSiteAdapter)
@@ -190,6 +198,7 @@ class AuthorizeMixinTestCase(unittest.TestCase):
         site_adapter_mock.render_auth_page.return_value = response_mock
 
         auth_mixin = AuthorizeMixin(site_adapter=site_adapter_mock)
+        auth_mixin.client = client_mock
         result = auth_mixin.authorize(Mock(spec=Request), response_mock,
                                       environ={}, scopes=[])
 
@@ -209,6 +218,9 @@ class AuthorizationCodeAuthHandlerTestCase(unittest.TestCase):
 
         auth_code_store_mock = Mock(spec=AuthCodeStore)
 
+        client = Client(identifier="abc", secret="xyz",
+                        redirect_uris=[redirect_uri])
+
         response_mock = Mock(spec=Response)
 
         request_mock = Mock(spec=Request)
@@ -231,14 +243,14 @@ class AuthorizationCodeAuthHandlerTestCase(unittest.TestCase):
             token_generator=token_generator_mock
         )
 
-        handler.client = Client(identifier="abc", secret="xyz",
-                                redirect_uris=[redirect_uri])
+        handler.client = client
         handler.state = state
         response = handler.process(request_mock, response_mock, environ)
 
         token_generator_mock.generate.assert_called_with()
         site_adapter_mock.authenticate.assert_called_with(request_mock,
-                                                          environ, scopes)
+                                                          environ, scopes,
+                                                          client)
         self.assertTrue(auth_code_store_mock.save_code.called)
         self.assertEqual(response.status_code, 302)
         self.assertEqual(response.body, "")
@@ -252,6 +264,8 @@ class AuthorizationCodeAuthHandlerTestCase(unittest.TestCase):
         response_mock = Mock(spec=Response)
         scopes = ["scopes"]
 
+        client_mock = Mock(spec=Client)
+
         request_mock = Mock(spec=Request)
 
         scope_handler_mock = Mock(Scope)
@@ -266,12 +280,14 @@ class AuthorizationCodeAuthHandlerTestCase(unittest.TestCase):
             scope_handler=scope_handler_mock, site_adapter=site_adapter_mock,
             token_generator=Mock()
         )
+        handler.client = client_mock
         response = handler.process(request_mock, response_mock, environ)
 
         site_adapter_mock.render_auth_page.assert_called_with(request_mock,
                                                               response_mock,
                                                               environ,
-                                                              scopes)
+                                                              scopes,
+                                                              client_mock)
         self.assertEqual(response, response_mock)
 
     def test_redirect_oauth_error(self):
@@ -801,7 +817,6 @@ class ImplicitGrantTestCase(unittest.TestCase):
 
 class ImplicitGrantHandlerTestCase(unittest.TestCase):
     def test_process_redirect_with_token(self):
-        client_id = "abc"
         environ = {"session": "data"}
         redirect_uri = "http://callback"
         scopes = ["scopes"]
@@ -810,6 +825,9 @@ class ImplicitGrantHandlerTestCase(unittest.TestCase):
 
         access_token_store_mock = Mock(spec=AccessTokenStore)
 
+        client = Client(identifier="abc", secret="xyz",
+                        redirect_uris=[redirect_uri])
+
         request_mock = Mock(spec=Request)
 
         responseMock = Mock(spec=Response)
@@ -831,12 +849,12 @@ class ImplicitGrantHandlerTestCase(unittest.TestCase):
             client_authenticator=Mock(), scope_handler=scope_handler_mock,
             site_adapter=site_adapter_mock,
             token_generator=token_generator_mock)
-        handler.client = Client(identifier="abc", secret="xyz",
-                                redirect_uris=[redirect_uri])
+        handler.client = client
         result_response = handler.process(request_mock, responseMock, environ)
 
         site_adapter_mock.authenticate.assert_called_with(request_mock,
-                                                          environ, scopes)
+                                                          environ, scopes,
+                                                          client)
 
         access_token, = access_token_store_mock.save_token.call_args[0]
         self.assertTrue(isinstance(access_token, AccessToken))
@@ -934,6 +952,8 @@ class ImplicitGrantHandlerTestCase(unittest.TestCase):
         scopes = ["scopes"]
         environ = {"session": "data"}
 
+        client_mock = Mock(spec=Client)
+
         request_mock = Mock(spec=Request)
 
         response_mock = Mock(spec=Response)
@@ -950,14 +970,17 @@ class ImplicitGrantHandlerTestCase(unittest.TestCase):
             scope_handler=scope_handler_mock, site_adapter=site_adapter_mock,
             token_generator=Mock()
         )
+        handler.client = client_mock
         result_response = handler.process(request_mock, response_mock, environ)
 
         site_adapter_mock.authenticate.assert_called_with(request_mock,
-                                                          environ, scopes)
+                                                          environ, scopes,
+                                                          client_mock)
         site_adapter_mock.render_auth_page.assert_called_with(request_mock,
                                                               response_mock,
                                                               environ,
-                                                              scopes)
+                                                              scopes,
+                                                              client_mock)
         self.assertEqual(result_response, response_mock)
 
     def test_process_user_denied_access(self):
@@ -1057,6 +1080,7 @@ class ResourceOwnerGrantTestCase(unittest.TestCase):
 class ResourceOwnerGrantHandlerTestCase(unittest.TestCase):
     def test_process(self):
         access_token = "0aef"
+        client = Client(identifier="abc", secret="xyz")
         expected_response_body = {"access_token": access_token,
                                   "token_type": "Bearer"}
         scopes = ["scope"]
@@ -1085,11 +1109,11 @@ class ResourceOwnerGrantHandlerTestCase(unittest.TestCase):
             scope_handler=scope_handler_mock,
             site_adapter=site_adapter_mock,
             token_generator=token_generator_mock)
-        handler.client = Client(identifier="abc", secret="xyz")
+        handler.client = client
         result = handler.process(request_mock, response_mock, {})
 
         site_adapter_mock.authenticate.assert_called_with(request_mock, {},
-                                                          scopes)
+                                                          scopes, client)
         token_generator_mock.create_access_token_data.assert_called_with(ResourceOwnerGrant.grant_type)
         access_token, = access_token_store_mock.save_token.call_args[0]
         self.assertTrue(isinstance(access_token, AccessToken))
@@ -1107,6 +1131,7 @@ class ResourceOwnerGrantHandlerTestCase(unittest.TestCase):
     @patch("time.time", mock_time)
     def test_process_with_refresh_token(self):
         access_token = "0aef"
+        client = Client(identifier="abc", secret="xyz")
         expected_response_body = {"access_token": access_token,
                                   "token_type": "Bearer",
                                   "refresh_token": "wxyz", "expires_in": 600}
@@ -1138,11 +1163,11 @@ class ResourceOwnerGrantHandlerTestCase(unittest.TestCase):
             scope_handler=scope_handler_mock,
             site_adapter=site_adapter_mock,
             token_generator=token_generator_mock)
-        handler.client = Client(identifier="abc", secret="xyz")
+        handler.client = client
         result = handler.process(request_mock, response_mock, {})
 
         site_adapter_mock.authenticate.assert_called_with(request_mock, {},
-                                                          scopes)
+                                                          scopes, client)
         token_generator_mock.create_access_token_data.assert_called_with(ResourceOwnerGrant.grant_type)
         access_token, = access_token_store_mock.save_token.call_args[0]
         self.assertTrue(isinstance(access_token, AccessToken))

pip install -e .[dev]
parse_log_pytest
requirements.txt
pytest numpy>=1.16.0 pandas>=1.0.0
apt-get update apt-get install -y gcc
3.9
requirements.txt
pytest --no-header -rA --tb=line --color=no -p no:cacheprovider -W ignore::DeprecationWarning
async-timeout==5.0.1
dnspython==2.7.0
exceptiongroup==1.2.2
iniconfig==2.1.0
mock==5.2.0
mysql-connector-python @ http://dev.mysql.com/get/Downloads/Connector-Python/mysql-connector-python-1.1.7.tar.gz#sha256=66f9aeadf2b908be0e31bf683cfa199c1c13401eb7c0acce7cec56d75d76e24a
nose==1.3.7
numpy==2.0.2
packaging==24.2
pandas==2.2.3
pluggy==1.5.0
pymongo==4.11.3
pytest==8.3.5
python-dateutil==2.9.0.post0
-e git+https://github.com/wndhydrnt/python-oauth2.git@f37a26ccb2a0bd5c6682a798f0e1669d75aacd5a#egg=python_oauth2
pytz==2025.2
redis==5.2.1
six==1.17.0
tomli==2.2.1
tornado==6.4.2
tzdata==2025.2

name: python-oauth2
channels:
  - defaults
  - https://repo.anaconda.com/pkgs/main
  - https://repo.anaconda.com/pkgs/r
  - conda-forge
dependencies:
  - _libgcc_mutex=0.1=main
  - _openmp_mutex=5.1=1_gnu
  - ca-certificates=2025.2.25=h06a4308_0
  - ld_impl_linux-64=2.40=h12ee557_0
  - libffi=3.4.4=h6a678d5_1
  - libgcc-ng=11.2.0=h1234567_1
  - libgomp=11.2.0=h1234567_1
  - libstdcxx-ng=11.2.0=h1234567_1
  - ncurses=6.4=h6a678d5_0
  - openssl=3.0.16=h5eee18b_0
  - pip=25.0=py39h06a4308_0
  - python=3.9.21=he870216_1
  - readline=8.2=h5eee18b_0
  - setuptools=75.8.0=py39h06a4308_0
  - sqlite=3.45.3=h5eee18b_0
  - tk=8.6.14=h39e8969_0
  - wheel=0.45.1=py39h06a4308_0
  - xz=5.6.4=h5eee18b_1
  - zlib=1.2.13=h5eee18b_1
  - pip:
      - async-timeout==5.0.1
      - dnspython==2.7.0
      - exceptiongroup==1.2.2
      - iniconfig==2.1.0
      - mock==5.2.0
      - mysql-connector-python==1.1.7
      - nose==1.3.7
      - numpy==2.0.2
      - packaging==24.2
      - pandas==2.2.3
      - pluggy==1.5.0
      - pymongo==4.11.3
      - pytest==8.3.5
      - python-dateutil==2.9.0.post0
      - pytz==2025.2
      - redis==5.2.1
      - six==1.17.0
      - tomli==2.2.1
      - tornado==6.4.2
      - tzdata==2025.2
prefix: /opt/conda/envs/python-oauth2

oauth2/test/functional/test_authorization_code.py::AuthorizationCodeTestCase::test_tornado oauth2/test/functional/test_authorization_code.py::AuthorizationCodeTestCase::test_wsgi oauth2/test/test_grant.py::AuthorizationCodeAuthHandlerTestCase::test_process oauth2/test/test_grant.py::AuthorizationCodeAuthHandlerTestCase::test_process_not_confirmed oauth2/test/test_grant.py::ImplicitGrantHandlerTestCase::test_process_redirect_with_token oauth2/test/test_grant.py::ImplicitGrantHandlerTestCase::test_process_unconfirmed oauth2/test/test_grant.py::ResourceOwnerGrantHandlerTestCase::test_process oauth2/test/test_grant.py::ResourceOwnerGrantHandlerTestCase::test_process_with_refresh_token
oauth2/test/test_grant.py::AuthorizationCodeGrantTestCase::test_create_auth_handler oauth2/test/test_grant.py::AuthorizationCodeGrantTestCase::test_create_no_match oauth2/test/test_grant.py::AuthorizationCodeGrantTestCase::test_create_token_handler oauth2/test/test_grant.py::AuthRequestMixinTestCase::test_read_validate_params_all_valid oauth2/test/test_grant.py::AuthorizeMixinTestCase::test_authorize_dict_return oauth2/test/test_grant.py::AuthorizeMixinTestCase::test_authorize_tuple_return oauth2/test/test_grant.py::AuthorizeMixinTestCase::test_authorize_user_denied_access oauth2/test/test_grant.py::AuthorizeMixinTestCase::test_authorize_user_not_authenticated oauth2/test/test_grant.py::AuthorizationCodeAuthHandlerTestCase::test_redirect_oauth_error oauth2/test/test_grant.py::AuthorizationCodeTokenHandlerTestCase::test_process_no_refresh_token oauth2/test/test_grant.py::AuthorizationCodeTokenHandlerTestCase::test_process_with_refresh_token oauth2/test/test_grant.py::AuthorizationCodeTokenHandlerTestCase::test_process_with_unique_access_token oauth2/test/test_grant.py::AuthorizationCodeTokenHandlerTestCase::test_process_with_unique_access_token_different_scope oauth2/test/test_grant.py::AuthorizationCodeTokenHandlerTestCase::test_process_with_unique_access_token_expired_token oauth2/test/test_grant.py::AuthorizationCodeTokenHandlerTestCase::test_process_with_unique_access_token_no_user_id oauth2/test/test_grant.py::AuthorizationCodeTokenHandlerTestCase::test_process_with_unique_access_token_not_found oauth2/test/test_grant.py::AuthorizationCodeTokenHandlerTestCase::test_read_validate_params oauth2/test/test_grant.py::AuthorizationCodeTokenHandlerTestCase::test_read_validate_params_missing_code oauth2/test/test_grant.py::AuthorizationCodeTokenHandlerTestCase::test_read_validate_params_no_auth_code_found oauth2/test/test_grant.py::AuthorizationCodeTokenHandlerTestCase::test_read_validate_params_token_expired oauth2/test/test_grant.py::AuthorizationCodeTokenHandlerTestCase::test_read_validate_params_unknown_code oauth2/test/test_grant.py::AuthorizationCodeTokenHandlerTestCase::test_read_validate_params_wrong_redirect_uri_in_code_data oauth2/test/test_grant.py::ImplicitGrantTestCase::test_create_matching_response_type oauth2/test/test_grant.py::ImplicitGrantTestCase::test_create_not_matching_response_type oauth2/test/test_grant.py::ImplicitGrantHandlerTestCase::test_process_redirect_with_state oauth2/test/test_grant.py::ImplicitGrantHandlerTestCase::test_process_user_denied_access oauth2/test/test_grant.py::ImplicitGrantHandlerTestCase::test_process_with_scope oauth2/test/test_grant.py::ImplicitGrantHandlerTestCase::test_redirect_oauth_error oauth2/test/test_grant.py::ResourceOwnerGrantTestCase::test_call oauth2/test/test_grant.py::ResourceOwnerGrantTestCase::test_call_no_resource_request oauth2/test/test_grant.py::ResourceOwnerGrantHandlerTestCase::test_handle_error_owner_not_authenticated oauth2/test/test_grant.py::ResourceOwnerGrantHandlerTestCase::test_process_invalid_user oauth2/test/test_grant.py::ResourceOwnerGrantHandlerTestCase::test_process_redirect_with_scope oauth2/test/test_grant.py::ResourceOwnerGrantHandlerTestCase::test_read_validate_params oauth2/test/test_grant.py::ScopeTestCase::test_compare_invalid_scope_requested oauth2/test/test_grant.py::ScopeTestCase::test_compare_scopes_equal oauth2/test/test_grant.py::ScopeTestCase::test_compare_valid_scope_subset oauth2/test/test_grant.py::ScopeTestCase::test_parse_scope_default_on_no_matching_scopes oauth2/test/test_grant.py::ScopeTestCase::test_parse_scope_default_on_no_scope oauth2/test/test_grant.py::ScopeTestCase::test_parse_scope_exception_on_available_scopes_no_scope_given oauth2/test/test_grant.py::ScopeTestCase::test_parse_scope_no_value_on_no_scope_no_default oauth2/test/test_grant.py::ScopeTestCase::test_parse_scope_scope_present_in_body oauth2/test/test_grant.py::ScopeTestCase::test_parse_scope_scope_present_in_query oauth2/test/test_grant.py::RefreshTokenTestCase::test_call oauth2/test/test_grant.py::RefreshTokenTestCase::test_call_other_grant_type oauth2/test/test_grant.py::RefreshTokenTestCase::test_call_wrong_path oauth2/test/test_grant.py::RefreshTokenHandlerTestCase::test_process_no_reissue oauth2/test/test_grant.py::RefreshTokenHandlerTestCase::test_process_with_reissue oauth2/test/test_grant.py::RefreshTokenHandlerTestCase::test_read_validate_params oauth2/test/test_grant.py::RefreshTokenHandlerTestCase::test_read_validate_params_expired_refresh_token oauth2/test/test_grant.py::RefreshTokenHandlerTestCase::test_read_validate_params_invalid_refresh_token oauth2/test/test_grant.py::RefreshTokenHandlerTestCase::test_read_validate_params_no_refresh_token oauth2/test/test_grant.py::ClientCredentialsGrantTestCase::test_call oauth2/test/test_grant.py::ClientCredentialsGrantTestCase::test_call_other_grant_type oauth2/test/test_grant.py::ClientCredentialsGrantTestCase::test_call_wrong_request_path oauth2/test/test_grant.py::ClientCredentialsHandlerTestCase::test_process oauth2/test/test_grant.py::ClientCredentialsHandlerTestCase::test_process_with_refresh_token oauth2/test/test_grant.py::ClientCredentialsHandlerTestCase::test_read_validate_params
README.rst docs/examples/tornado_server.py oauth2/web/__init__.py docs/examples/resource_owner_grant.py setup.py docs/examples/authorization_code_grant.py oauth2/grant.py CHANGELOG.md docs/migration.rst docs/examples/implicit_grant.py docs/examples/base_server.py
README.rst docs/examples/tornado_server.py oauth2/web/__init__.py docs/examples/resource_owner_grant.py setup.py docs/examples/authorization_code_grant.py oauth2/grant.py CHANGELOG.md docs/migration.rst docs/examples/implicit_grant.py docs/examples/base_server.py