def fetch_az_users(self, user_ids=None):
        """
        Fetches ALL valid users from auth0'z database
        Returns list of user attributes
        """
        # Memory cached?
        if self.az_users is not None:
            return self.az_users

        # S3 cached?
        self.get_s3_cache()
        if self.s3_cache is not None:
            self.az_users = self.s3_cache["az_users"]
            return self.az_users
        # Don't use cache for just one user
        if self.az_users is not None and (user_ids is not None and len(user_ids) != 1):
            return self.az_users

        # Not cached, fetch it
        if user_ids is not None and len(user_ids) != 1:
            self.s3_cache_require_update = True
        az_api_url = self.config("AUTHZERO_API", namespace="cis", default="auth-dev.mozilla.auth0.com")
        az_client_id = self.secret_manager.secret("az_client_id")
        az_client_secret = self.secret_manager.secret("az_client_secret")
        az_fields = self.az_cis_fields.keys()

        # Build the connection query (excludes LDAP)
        # Excluded: "Mozilla-LDAP", "Mozilla-LDAP-Dev"
        # Excluded: Old users without any group
        # This can also be retrieved from /api/v2/connections
        # Ignore non-verified `email` (such as unfinished passwordless flows) as we don't consider these to be valid
        # users
        max_date = datetime.utcnow() - timedelta(days=31)  # maximum login length + 1 day
        max_date_str = max_date.strftime("%Y-%m-%d")
        exclusion_query = (
            f"logins_count:[2 TO *] AND NOT last_login:[* TO {max_date_str}] AND "
            '(groups:(everyone) OR (NOT _exists_:"groups"))'
        )
        az_query = exclusion_query + " AND email_verified:true AND ("
        t = ""
        for azc in self.az_whitelisted_connections:
            az_query = az_query + t + 'identities.connection:"{}"'.format(azc)
            t = " OR "
        az_query += ")"
        # NOTE XXX: There is no way to tell auth0's ES "don't include matches where the first identity.connection is a
        # blacklisted connection", so we do this instead. This 100% relies on auth0 user_ids NOT being opaque,
        # unfortunately
        az_query += ' AND NOT (user_id:"ad|*")'

        # Build query for user_ids if some are specified (else it gets all of them)
        # NOTE: We can't query all that many users because auth0 uses a GET query which is limited in size by httpd
        # (nginx - 8kb by default)
        if user_ids and len(user_ids) > 6:
            logger.warning(
                "Cannot query the requested number of user_ids from auth0, query would be too large. "
                "Querying all user_ids instead."
            )
            user_ids = None
        # we had to add this because it gets called by the CIS-New-User hook, where the query wouldn't work
        # because exclusion_query excludes users who have only a single login success
        elif len(user_ids) == 1:
            logger.info("Restricting auth0 user query to single user_id: {}".format(user_ids[0]))
            az_query = f'user_id:"{user_ids[0]}"'
        elif user_ids:
            logger.info("Restricting auth0 user query to user_ids: {}".format(user_ids))

            # e.g.: user_id:"email|foo" OR user_id:"email|bar" OR user_id:"ad|Mozilla-LDAP|baz"
            or_joined_user_query = " OR ".join([f'user_id:"{u}"' for u in user_ids])
            az_query += f" AND ({or_joined_user_query})"

        logger.debug("About to get Auth0 user list")
        az_getter = GetToken(az_api_url)
        az_token = az_getter.client_credentials(az_client_id, az_client_secret, "https://{}/api/v2/".format(az_api_url))
        auth0 = Auth0(az_api_url, az_token["access_token"])

        # Query the entire thing
        logger.info("Querying auth0 user database, query is: {}".format(az_query))
        user_list = []
        # This is an artificial upper limit of 100*9999 (per_page*page) i.e. 999 900 users max - just in case things
        # go wrong
        retries = 15
        backoff = 20
        for p in range(0, 9999):
            tmp = None
            try:
                tmp = auth0.users.list(page=p, per_page=100, fields=az_fields, q=az_query)["users"]
                logger.debug("Requesting auth0 user list, at page {}".format(p))
            except Auth0Error as e:
                # 429 is Rate limit exceeded and we can still retry
                if (e.error_code == 429 or e.status_code == 429) and retries > 0:
                    backoff += 1
                    logger.debug(
                        "Rate limit exceeded, backing off for {} seconds, retries left {} error: {}".format(
                            backoff, retries, e
                        )
                    )
                    retries -= 1
                    time.sleep(backoff)
                else:
                    logger.warning("Error: {}".format(e))
                    raise

            if tmp == [] or tmp is None:
                # stop when our page is empty
                logger.debug("Crawled {} pages from auth0 users API".format(p))
                break
            else:
                user_list.extend(tmp)
        logger.info("Received {} users from auth0".format(len(user_list)))

        self.az_users = user_list

        return self.az_users