Skip to content

Instantly share code, notes, and snippets.

Show Gist options
  • Save amelieykw/6116ca8ef7279206382a76fd790c1aa1 to your computer and use it in GitHub Desktop.
Save amelieykw/6116ca8ef7279206382a76fd790c1aa1 to your computer and use it in GitHub Desktop.
[Django - What is the Pythonic way of storing credentials in code?] #Django #Python #storeCredentialsInCode

Question

To further elaborate on my question, imagine you are working on a Python project that needs a password to connect to a database, or a "client secret" to connect to a webservice. Where is the best place to store that information so that you don't inadvertently share it when distributing code?

The most common pattern I've seen is to embed it directly in the Python script, but then leave it blank, with a comment to fill it in yourself.

consumer_secret='' #Fill this in with your own credentials

Coming from PHP, the standard method was to store credentials as variables in a separate file, and then import to a script. That way you could easily "gitignore" that file, but I don't see this very often in Python.

Answers

1st floor

belak51 belak 13 points·4 years ago· edited 4 years ago

In this instance, I think that it depends on the application. There are a few different main types of applications (at least types that I write).

  1. Web service, written using flask, django or some other framework. For these I generally use environment variables, then load all of them in a config.py, or something like that. For instance consumer_secret = os.environ['SECRET'] would load the environment var SECRET into that variable. It has the added advantage of throwing an error if the variable is not set, making it simple to find stuff where not all the options are configured. This makes it simple to deploy. Heroku passes most of it's other service information through environment variables, so you can even use their tools to run your projects even if you don't use heroku. If you want to do this, you need something like forego or foreman. Then you can make a .env file with SECRET=*!)(8sdoaiu09109u09, a Procfile with web: command to start your app and your app will start with foreman start. You can also run arbitrary commands with foreman run command here

  2. User facing tools. For these, python has a builtin config file parser. I haven't used this too much, but from what I can tell, it's pretty easy to work with. Once you have a file to store it in, you can separate config by sections and if the section doesn't create, you can populate it and save the file. You can also use a command line flag to load a separate config file if you want with argparse.

  3. Internal tools. Either of the previous options works. It really boils down to personal preference at this point.

Hope this helps.

  • EDIT: formatting
  • EDIT 2: Added argparse info.
  • EDIT 3: Just noticed your comment on leaving a blank template. This is bad for a number of reasons. Firstly, if something is added to the config template and then pushed, users will not be required to update their configs, so there's a possibility that you won't even run into an issue until they're running the program (if you use import config and then try to use config.something in code, there will be an error). It's much easier to catch configuration issues at startup. Secondly, if you want to run more than one instance of the program, you need a separate copy of the code.

1st floor Reply

mercer22 1 point· 4 years ago

I had never thought of storing that info as environmental variables. Neat idea.

2nd floor

kroe761 8 points·4 years ago·edited 4 years ago

I like using ConfigParser. You would make a config file, and store it somewhere else that you can make as easy/difficult to edit as you want (like the etc folder). it would be something like

[configuration]
password = 11111

and then, on your actual python script, your would import that data like this

import ConfigParser
config = ConfigParser.ConfigParser()
config.read("/etc/config.txt")
pass = config.get("configuration","password")

and then your variable pass now has the password. Nice and clean

2nd floor Reply

lucidguppy 1 point· 4 years ago

This is nice because you can keep a debug.txt config file in source control - and replace it with your own.

teachMe 4 points· 4 years ago

Just be mindful that pass is a language keyword, and even if it's possible, you're not going to want to shadow keywords, as a programming habit.

3rd floor

4 years ago For a very simple solution, create a Python file, say, credentials.py, in the same directory as your script. Write a dictionary with your passwords, like this:

login = {
    'password' : 'YOUR_PASSWORD',
    'consumer_secret' : 'YOUR_SECRET'
}

and so on. Then in your script file:

import credentials

consumer_secret = credentials.login['consumer_secret']

Make sure you keep your credentials file out of any revisioning. Gitignore if needed.

4th floor

Samus_git2samus 3 points· 4 years ago

what Django people usually do is to have a Python script (usually called local_settings.py) that is explicitly excluded from the repository and it gets imported into the actual settings file that is tracked.

4th floor Reply

shidarin shidarin 2 points·4 years ago

Yeah, I use a config .ini file which contains both the credentials and the normal settings. Then I add that config.ini to git ignore, and an empty sample_config.ini with no values to the repo.

5th floor

n8henrie n8henrie 1 point· 4 years ago

If it's just a script for personal use, I really like keyring. Interfaces with Keychain.app on my Mac, has a very user friendly interface, and let's me use a simple my_pass = keyring.get_password('reddit', 'n8henrie').

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment