diff --git a/jupyterhub/services/service.py b/jupyterhub/services/service.py index acea33f6..f556b6da 100644 --- a/jupyterhub/services/service.py +++ b/jupyterhub/services/service.py @@ -192,9 +192,15 @@ class Service(LoggingConfigurable): oauth_roles = List( help="""OAuth allowed roles. - - List of roles that are passed to generated tokens if the service act as an OAuth client - on behalf of users""" + + This sets the maximum and default roles + assigned to oauth tokens issued for this service + (i.e. tokens stored in browsers after authenticating with the server), + defining what actions the service can take on behalf of logged-in users. + + Default is an empty list, meaning minimal permissions to identify users, + no actions can be taken on their behalf. + """ ).tag(input=True) api_token = Unicode( diff --git a/jupyterhub/spawner.py b/jupyterhub/spawner.py index 2c4d4581..d96dd54d 100644 --- a/jupyterhub/spawner.py +++ b/jupyterhub/spawner.py @@ -219,10 +219,19 @@ class Spawner(LoggingConfigurable): oauth_client_id = Unicode() handler = Any() - allowed_roles = List( - help="""OAuth allowed roles for single-user servers - """ - ).tag(input=True) + oauth_roles = Union( + [Callable(), List()], + help="""Allowed roles for oauth tokens. + + This sets the maximum and default roles + assigned to oauth tokens issued by a single-user server's + oauth client (i.e. tokens stored in browsers after authenticating with the server), + defining what actions the server can take on behalf of logged-in users. + + Default is an empty list, meaning minimal permissions to identify users, + no actions can be taken on their behalf. + """, + ).tag(config=True) will_resume = Bool( False, diff --git a/jupyterhub/tests/test_spawner.py b/jupyterhub/tests/test_spawner.py index 9d06a0e4..3721ccb4 100644 --- a/jupyterhub/tests/test_spawner.py +++ b/jupyterhub/tests/test_spawner.py @@ -430,5 +430,5 @@ async def test_hub_connect_url(db): async def test_spawner_oauth_roles(app): allowed_roles = ['lotsa', 'roles'] - spawner = new_spawner(app.db, allowed_roles=allowed_roles) - assert spawner.allowed_roles == allowed_roles + spawner = new_spawner(app.db, oauth_roles=allowed_roles) + assert spawner.oauth_roles == allowed_roles diff --git a/jupyterhub/user.py b/jupyterhub/user.py index 9c31da6b..fce76a89 100644 --- a/jupyterhub/user.py +++ b/jupyterhub/user.py @@ -564,11 +564,16 @@ class User: oauth_client = oauth_provider.fetch_by_client_id(client_id) # create a new OAuth client + secret on every launch # containers that resume will be updated below + + allowed_roles = spawner.oauth_roles + if callable(allowed_roles): + allowed_roles = allowed_roles(spawner) + oauth_provider.add_client( client_id, api_token, url_path_join(self.url, server_name, 'oauth_callback'), - allowed_roles=spawner.allowed_roles, + allowed_roles=allowed_roles, description="Server at %s" % (url_path_join(self.base_url, server_name) + '/'), )