    def validate_scopes(self, client_id, scopes, client, request, *args, **kwargs):
        """Ensure the client is authorized access to requested scopes.
        :param client_id: Unicode client identifier
        :param scopes: List of 'raw' scopes (defined by you)
        :param client: Client object set by you, see authenticate_client.
        :param request: The HTTP Request (oauthlib.common.Request)
        :rtype: True or False
        Method is used by all core grant types:
            - Authorization Code Grant
            - Implicit Grant
            - Resource Owner Password Credentials Grant
            - Client Credentials Grant
        """
        orm_client = (
            self.db.query(orm.OAuthClient).filter_by(identifier=client_id).one_or_none()
        )
        if orm_client is None:
            app_log.warning("No such oauth client %s", client_id)
            return False

        requested_scopes = set(scopes)
        # explicitly allow 'identify', which was the only allowed scope previously
        # requesting 'identify' gets no actual permissions other than self-identification
        if "identify" in requested_scopes:
            app_log.warning(
                f"Ignoring deprecated 'identify' scope, requested by {client_id}"
            )
            requested_scopes.discard("identify")

        # TODO: handle roles->scopes transition
        # In 2.x, `?scopes=` only accepted _role_ names,
        # but in 3.0 we accept and prefer scopes.
        # For backward-compatibility, we still accept both.
        # Should roles be deprecated here, or kept as a convenience?
        try:
            _check_scopes_exist(requested_scopes)
        except KeyError as e:
            # scopes don't exist, maybe they are role names
            requested_roles = list(
                self.db.query(orm.Role).filter(orm.Role.name.in_(requested_scopes))
            )
            if len(requested_roles) != len(requested_scopes):
                # did not find roles
                app_log.warning(f"No such scopes: {requested_scopes}")
                return False
            app_log.info(
                f"OAuth client {client_id} requesting roles: {requested_scopes}"
            )
            requested_scopes = roles_to_scopes(requested_roles)

        client_allowed_scopes = set(orm_client.allowed_scopes)

        # scope resolution only works if we have a user defined
        user = request.user or getattr(self, "_current_user")

        # always grant reading the token-owner's name
        # and accessing the service itself
        required_scopes = {*identify_scopes(), *access_scopes(orm_client)}
        requested_scopes.update(required_scopes)
        client_allowed_scopes.update(required_scopes)

        allowed_scopes, disallowed_scopes = _resolve_requested_scopes(
            requested_scopes,
            client_allowed_scopes,
            user=user.orm_user,
            client=orm_client,
            db=self.db,
        )

        if disallowed_scopes:
            app_log.error(
                f"Scope(s) not allowed for {client_id}: {', '.join(disallowed_scopes)}"
            )
            return False

        # store resolved scopes on request
        app_log.debug(
            f"Allowing request for scope(s) for {client_id}:  {','.join(requested_scopes) or '[]'}"
        )
        request.scopes = requested_scopes
        return True
Ensure the client is authorized access to requested scopes.
:param client_id: Unicode client identifier
:param scopes: List of 'raw' scopes (defined by you)
:param client: Client object set by you, see authenticate_client.
:param request: The HTTP Request (oauthlib.common.Request)
:rtype: True or False
Method is used by all core grant types:
- Authorization Code Grant
- Implicit Grant
- Resource Owner Password Credentials Grant
- Client Credentials Grant
jupyterhub/oauth/provider.py