def _anonymous_xsrf_id(handler):
    """Generate an appropriate xsrf token id for an anonymous request

    Currently uses hash of request ip and user-agent

    These are typically used only for the initial login page,
    and don't need to be perfectly unique, just:

    1. reasonably stable for a single user for the duration of a login
       (a few requests, which may pass through different proxies)
    2. somewhat unlikely to be shared across users

    These are typically used only for the initial login page,
    so only need to be valid for a few seconds to a few minutes
    (enough to submit a login form with MFA).
    """
    hasher = hashlib.sha256()
    ip = ip_to_hash = handler.request.remote_ip
    try:
        ip_addr = ip_address(ip)
    except ValueError as e:
        # invalid ip ?!
        app_log.error("Error parsing remote ip %r: %s", ip, e)
    else:
        # if the ip is private (e.g. a cluster ip),
        # this is almost certainly a proxy ip and not useful
        # for distinguishing request origin.
        # A proxy has the double downside of multiple replicas
        # meaning the value can change from one request to the next for the
        # same 'true' origin, resulting in unavoidable xsrf mismatch errors
        for cidr in _anonymous_ip_cidrs:
            if ip_addr in cidr:
                # use matching cidr
                ip_to_hash = str(cidr)
                break
    hasher.update(ip_to_hash.encode("ascii"))
    for name in _anonymous_id_headers:
        header = handler.request.headers.get(name, "")
        hasher.update(header.encode("utf8", "replace"))
        # field delimiter (should be something not valid utf8)
        hasher.update(b"\xff")
    return base64.urlsafe_b64encode(hasher.digest()).decode("ascii")
Generate an appropriate xsrf token id for an anonymous request

Currently uses hash of request ip and user-agent

These are typically used only for the initial login page,
and don't need to be perfectly unique, just:

1. reasonably stable for a single user for the duration of a login
(a few requests, which may pass through different proxies)
2. somewhat unlikely to be shared across users

These are typically used only for the initial login page,
so only need to be valid for a few seconds to a few minutes
(enough to submit a login form with MFA).
jupyterhub/_xsrf_utils.py