docs: def confidential_login(credentials=None, client_id=None, client_secret=None, services=None,
                         make_clients=True, token_dir=DEFAULT_CRED_PATH):
      """Log in to Globus services as a confidential client
      (a client with its own login information).
  
      Arguments:
          credentials (str or dict): A string filename, string JSON, or dictionary
                  with credential and config information.
                  By default, uses the ``DEFAULT_CRED_FILENAME`` and token_dir.
                  Contains ``client_id``, ``client_secret``, and ``services`` as defined below.
          client_id (str): The ID of the client.
          client_secret (str): The client's secret for authentication.
          services (list of str): Services to authenticate with.
          make_clients (bool): If ``True``, will make and return appropriate clients
                  with generated tokens.
                  If ``False``, will only return authorizers.
                  **Default**: ``True``.
          token_dir (str): The path to the directory to save tokens in and look for
                  credentials by default.
                  **Default**: ``DEFAULT_CRED_PATH``.
  
      Returns:
          dict: The clients and authorizers requested, indexed by service name.
      """
      DEFAULT_CRED_FILENAME = "confidential_globus_login.json"
      # Read credentials if supplied
      if credentials:
          if type(credentials) is str:
              try:
                  with open(credentials) as cred_file:
                      creds = json.load(cred_file)
              except IOError:
                  try:
                      creds = json.loads(credentials)
                  except ValueError:
                      raise ValueError("Credentials unreadable or missing")
          elif type(credentials) is dict:
              creds = credentials
          else:
              try:
                  with open(os.path.join(os.getcwd(), DEFAULT_CRED_FILENAME)) as cred_file:
                      creds = json.load(cred_file)
              except IOError:
                  try:
                      with open(os.path.join(token_dir, DEFAULT_CRED_FILENAME)) as cred_file:
                          creds = json.load(cred_file)
                  except IOError:
                      raise ValueError("Credentials/configuration must be passed as a "
                                       "filename string, JSON string, or dictionary, or provided "
                                       "in '{}' or '{}'.".format(DEFAULT_CRED_FILENAME,
                                                                 token_dir))
          client_id = creds.get("client_id")
          client_secret = creds.get("client_secret")
          services = creds.get("services", services)
      if not client_id or not client_secret:
          raise ValueError("A client_id and client_secret are required.")
      if not services:
          services = []
      elif isinstance(services, str):
          services = [services]
  
      conf_client = globus_sdk.ConfidentialAppAuthClient(client_id, client_secret)
      servs = []
      for serv in services:
          serv = serv.lower().strip()
          if type(serv) is str:
              servs += serv.split(" ")
          else:
              servs += list(serv)
      # Translate services into scopes as possible
      scopes = [KNOWN_SCOPES.get(sc, sc) for sc in servs]
  
      # Make authorizers with every returned token
      all_authorizers = {}
      for scope in scopes:
          # TODO: Allow non-CC authorizers?
          try:
              all_authorizers[scope] = globus_sdk.ClientCredentialsAuthorizer(conf_client, scope)
          except Exception as e:
              print("Error: Cannot create authorizer for scope '{}' ({})".format(scope, str(e)))
      returnables = {}
      # Populate clients and named services
      # Only translate back services - if user provides scope directly, don't translate back
      # ex. transfer => urn:transfer.globus.org:all => transfer,
      #     but urn:transfer.globus.org:all !=> transfer
      for service in servs:
          token_key = KNOWN_SCOPES.get(service)
          # If the .by_resource_server key (token key) for the service was returned
          if token_key in all_authorizers.keys():
              # If there is an applicable client (all clients have known token key)
              # Pop from all_authorizers to remove from final return value
              if make_clients and KNOWN_CLIENTS.get(service):
                  try:
                      returnables[service] = KNOWN_CLIENTS[service](
                                                  authorizer=all_authorizers.pop(token_key),
                                                  http_timeout=STD_TIMEOUT)
                  except globus_sdk.GlobusAPIError as e:
                      print("Error: Unable to create {} client: {}".format(service, e.message))
              # If no applicable client, just translate the key
              else:
                  returnables[service] = all_authorizers.pop(token_key)
      # Add authorizers not associated with service to returnables
      returnables.update(all_authorizers)
  
      return returnables