diff --git a/oauthenticator/github.py b/oauthenticator/github.py index fcc63b3b..2d76bec5 100644 --- a/oauthenticator/github.py +++ b/oauthenticator/github.py @@ -126,7 +126,7 @@ def _userdata_url_default(self): https://docs.github.com/en/rest/reference/teams#list-teams-for-the-authenticated-user. Requires `read:org` to be set in `scope`. - + Note that authentication state is only be available to a `post_auth_hook` before being discarded unless configured to be persisted via `enable_auth_state`. For more information, see @@ -134,6 +134,18 @@ def _userdata_url_default(self): """, ) + populate_groups_from_teams = Bool( + False, + config=True, + help=""" + Populates JupyterHub groups from list of GitHub teams the user is a part of. + + Requires `read:org` to be set in `scope`. + + Requires `manage_groups` to be set to True. + """ + ) + # _deprecated_oauth_aliases is used by deprecation logic in OAuthenticator _deprecated_oauth_aliases = { "github_client_id": ("client_id", "0.1.0"), @@ -224,6 +236,9 @@ async def update_auth_model(self, auth_model): user_info["email"] = val["email"] break + + # https://docs.github.com/en/rest/teams/teams?apiVersion=2022-11-28#list-teams-for-the-authenticated-user + teams_url = f"{self.github_api}/user/teams?per_page=100" if self.populate_teams_in_auth_state: if "read:org" not in self.scope: # This means the "read:org" scope was not set, and we can't @@ -232,13 +247,22 @@ async def update_auth_model(self, auth_model): "read:org scope is required for populate_teams_in_auth_state functionality to work" ) else: - # https://docs.github.com/en/rest/teams/teams?apiVersion=2022-11-28#list-teams-for-the-authenticated-user - url = f"{self.github_api}/user/teams?per_page=100" - user_teams = await self._paginated_fetch(url, access_token, token_type) + user_teams = await self._paginated_fetch(teams_url, access_token, token_type) auth_model["auth_state"]["teams"] = user_teams + if self.manage_groups and self.populate_groups_from_teams: + if "read:org" not in self.scope: + # This means the "read:org" scope was not set, and we can't fetch teams + self.log.error( + "read:org scope is required for populate_groups_from_teams functionality to work" + ) + else: + user_teams = await self._paginated_fetch(teams_url, access_token, token_type) + auth_model["groups"] = user_teams + return auth_model + async def _paginated_fetch(self, api_url, access_token, token_type): """ Fetch all items via a paginated GitHub API call