--- title: separating credentials subtitle: You gotta keep 'em separated author: david marsh date: 2024-11-01 keywords: [python, security] abstract: Here's a way to keep your api credentials out of your Python code. --- Creating a credentials file is a great way to avoid putting your credentials directly into your python code. Here's one way to do it: ```python #!/usr/bin/env python3 #https://docs.python.org/3/library/configparser.html #create a config.ini like this: #[credentials] #ACCESS_ID = 12345678901234567890 #ACCESS_KEY = 1234567890123456789123456789012345678901 #ACCOUNT_NAME = example import configparser def main(): config = configparser.ConfigParser() config.read('config.ini') ACCESS_ID = config.get('credentials', 'ACCESS_ID') ACCESS_KEY = config.get('credentials', 'ACCESS_KEY') ACCOUNT_NAME = config.get('credentials', 'ACCOUNT_NAME') #print(ACCESS_ID, ACCESS_KEY, ACCOUNT_NAME) if __name__ == "__main__": main() ``` Here's a heap of improvements made by ChatGPT, all of which seem very sensible: ```python #!/usr/bin/env python3 # Example config.ini: # [credentials] # ACCESS_ID = 12345678901234567890 # ACCESS_KEY = 1234567890123456789123456789012345678901 # ACCOUNT_NAME = example import configparser import sys CONFIG_FILE = 'config.ini' def load_config(file_path=CONFIG_FILE): """Load configuration from a file.""" config = configparser.ConfigParser(interpolation=None) # Disable interpolation eg for % symbols try: with open(file_path) as config_file: config.read_file(config_file) except FileNotFoundError: sys.exit(f"Error: Configuration file '{file_path}' not found.") except configparser.Error as e: sys.exit(f"Error: Failed to parse config file '{file_path}': {e}") # Retrieve credentials, with error handling try: access_id = config.get('credentials', 'ACCESS_ID') access_key = config.get('credentials', 'ACCESS_KEY') account_name = config.get('credentials', 'ACCOUNT_NAME') except configparser.NoSectionError: sys.exit("Error: 'credentials' section missing in configuration file.") except configparser.NoOptionError as e: sys.exit(f"Error: Missing configuration option in 'credentials': {e}") return access_id, access_key, account_name def main(): access_id, access_key, account_name = load_config() # Process or print credentials here as needed print(access_id, access_key, account_name) if __name__ == "__main__": main() ```