    async def patch(self, user_name, server_name=None):
        """PATCH revokes permissions from single shares for a given server"""

        if server_name is None:
            # only GET supported `/shares/{user}` without specified server
            raise web.HTTPError(405)

        model = self.get_json_body() or {}
        try:
            request = ShareRevokeRequest(**model)
        except ValidationError as e:
            raise web.HTTPError(400, str(e))

        # TODO: check allowed/valid scopes

        scopes = request.scopes

        # resolve target spawner
        spawner = self._lookup_spawner(user_name, server_name)

        if request.user:
            # don't need to check read:user permissions for revocation
            share_with = self.find_user(request.user)
            if share_with is None:
                # No such user is the same as revoking
                self.log.warning(f"No such user: {request.user}")
                self.finish("{}")
                return
            share_with = share_with.orm_user
        elif request.group:
            share_with = orm.Group.find(self.db, name=request.group)
            if share_with is None:
                # No such group behaves the same as revoking no permissions
                self.log.warning(f"No such group: {request.group}")
                self.finish("{}")
                return

        share = orm.Share.revoke(self.db, spawner, share_with, scopes=scopes)
        if share:
            self.finish(json.dumps(self.share_model(share)))
        else:
            # empty dict if share deleted
            self.finish("{}")
PATCH revokes permissions from single shares for a given server
jupyterhub/apihandlers/shares.py