    async def init_users(self):
        """Load users into and from the database"""
        db = self.db

        if self.authenticator.enable_auth_state:
            # check that auth_state encryption is available
            # if it's not, exit with an informative error.
            ck = crypto.CryptKeeper.instance()
            try:
                ck.check_available()
            except Exception as e:
                self.exit(
                    f"auth_state is enabled, but encryption is not available: {e}"
                )

        # give the authenticator a chance to check its own config
        self.authenticator.check_allow_config()

        if self.admin_users and not self.authenticator.admin_users:
            self.log.warning(
                "\nJupyterHub.admin_users is deprecated since version 0.7.2."
                "\nUse Authenticator.admin_users instead."
            )
            self.authenticator.admin_users = self.admin_users
        admin_users = [
            self.authenticator.normalize_username(name)
            for name in self.authenticator.admin_users
        ]
        self.authenticator.admin_users = set(admin_users)  # force normalization
        for username in admin_users:
            if not self.authenticator.validate_username(username):
                raise ValueError(f"username {username!r} is not valid")

        new_users = []

        for name in admin_users:
            # ensure anyone specified as admin in config is admin in db
            user = orm.User.find(db, name)
            if user is None:
                user = orm.User(name=name, admin=True)
                db.add(user)
                roles.assign_default_roles(self.db, entity=user)
                new_users.append(user)
            else:
                user.admin = True

        # the admin_users config variable will never be used after this point.
        # only the database values will be referenced.
        allowed_users = [
            self.authenticator.normalize_username(name)
            for name in self.authenticator.allowed_users
        ]
        self.authenticator.allowed_users = set(allowed_users)  # force normalization
        for username in allowed_users:
            if not self.authenticator.validate_username(username):
                raise ValueError(f"username {username!r} is not valid")

        if self.authenticator.allowed_users and self.authenticator.admin_users:
            # make sure admin users are in the allowed_users set, if defined,
            # otherwise they won't be able to login
            self.authenticator.allowed_users |= self.authenticator.admin_users

        # add allowed users to the db
        for name in allowed_users:
            user = orm.User.find(db, name)
            if user is None:
                user = orm.User(name=name)
                new_users.append(user)
                db.add(user)

        db.commit()

        # Notify authenticator of all users.
        # This ensures Authenticator.allowed_users is up-to-date with the database.
        # This lets .allowed_users be used to set up initial list,
        # but changes to the allowed_users set can occur in the database,
        # and persist across sessions.
        total_users = 0
        blocked_users = self.authenticator.blocked_users
        for user in db.query(orm.User):
            if user.name in blocked_users:
                # don't call add_user with blocked users
                continue
            try:
                f = self.authenticator.add_user(user)
                if f:
                    await maybe_future(f)
            except Exception:
                self.log.exception("Error adding user %s already in db", user.name)
                if self.authenticator.delete_invalid_users:
                    self.log.warning(
                        "Deleting invalid user %s from the Hub database", user.name
                    )
                    db.delete(user)
                else:
                    self.log.warning(
                        dedent(
                            """
                    You can set
                        c.Authenticator.delete_invalid_users = True
                    to automatically delete users from the Hub database that no longer pass
                    Authenticator validation,
                    such as when user accounts are deleted from the external system
                    without notifying JupyterHub.
                    """
                        )
                    )
            else:
                total_users += 1
                # handle database upgrades where user.created is undefined.
                # we don't want to allow user.created to be undefined,
                # so initialize it to last_activity (if defined) or now.
                if not user.created:
                    user.created = user.last_activity or utcnow(with_tz=False)
        db.commit()

        # The allowed_users set and the users in the db are now the same.
        # From this point on, any user changes should be done simultaneously
        # to the allowed_users set and user db, unless the allowed set is empty (all users allowed).

        TOTAL_USERS.set(total_users)
Load users into and from the database
jupyterhub/app.py