class_docstr: Implementation of ZAP authentication for zmq connections.
  
  This authenticator class does not register with an event loop. As a result,
  you will need to manually call `handle_zap_message`::
  
      auth = zmq.Authenticator()
      auth.allow("127.0.0.1")
      auth.start()
      while True:
          await auth.handle_zap_msg(auth.zap_socket.recv_multipart())
  
  Alternatively, you can register `auth.zap_socket` with a poller.
  
  Since many users will want to run ZAP in a way that does not block the
  main thread, other authentication classes (such as :mod:`zmq.auth.thread`)
  are provided.
  
  Note:
  
  - libzmq provides four levels of security: default NULL (which the Authenticator does
    not see), and authenticated NULL, PLAIN, CURVE, and GSSAPI, which the Authenticator can see.
  - until you add policies, all incoming NULL connections are allowed.
    (classic ZeroMQ behavior), and all PLAIN and CURVE connections are denied.
  - GSSAPI requires no configuration.
class_docstr_tok: ["Implementation","of","ZAP","authentication","for","zmq","connections",".","This","authenticator","class","does","not","register","with","an","event","loop",".","As","a","result",",","you","will","need","to","manually","call","`","handle_zap_message","`",":",":","auth","=","zmq.Authenticator","(",")","auth.allow","(","``","127.0.0.1","''",")","auth.start","(",")","while","True",":","await","auth.handle_zap_msg","(","auth.zap_socket.recv_multipart","(",")",")","Alternatively",",","you","can","register","`","auth.zap_socket","`","with","a","poller",".","Since","many","users","will","want","to","run","ZAP","in","a","way","that","does","not","block","the","main","thread",",","other","authentication","classes","(","such","as",":","mod",":","`","zmq.auth.thread","`",")","are","provided",".","Note",":","-","libzmq","provides","four","levels","of","security",":","default","NULL","(","which","the","Authenticator","does","not","see",")",",","and","authenticated","NULL",",","PLAIN",",","CURVE",",","and","GSSAPI",",","which","the","Authenticator","can","see",".","-","until","you","add","policies",",","all","incoming","NULL","connections","are","allowed",".","(","classic","ZeroMQ","behavior",")",",","and","all","PLAIN","and","CURVE","connections","are","denied",".","-","GSSAPI","requires","no","configuration","."]
docstr: Send a ZAP reply to finish the authentication.
docstr_tok: ["Send","a","ZAP","reply","to","finish","the","authentication","."]
code: def _send_zap_reply(
      self,
      request_id: bytes,
      status_code: bytes,
      status_text: bytes,
      user_id: str = "anonymous",
  ) -> None:
      """Send a ZAP reply to finish the authentication."""
      user_id = user_id if status_code == b"200" else b""
      if isinstance(user_id, str):
          user_id = user_id.encode(self.encoding, "replace")
      metadata = b""  # not currently used
      self.log.debug(
          "ZAP reply code=%s text=%s", status_code, status_text
      )
      reply = [
          VERSION,
          request_id,
          status_code,
          status_text,
          user_id,
          metadata,
      ]
      self.zap_socket.send_multipart(reply)
  
imports: import logging
  import os
  from typing import Any, Awaitable, Dict, List, Optional, Set, Tuple, Union
  import zmq
  from zmq.error import _check_version
  from zmq.utils import z85
  from .certs import load_certificates
label_desc: Use image node_id 13 for calling the Authenticator obj's underlying member method code with example usage: obj._send_zap_reply(request_id, status_code, status_text, user_id) without return types