DEV Community

Cover image for How to protect your Django Secret and OAuth Keys [2024 revised]
vladyslav nykoliuk
vladyslav nykoliuk

Posted on • Updated on

How to protect your Django Secret and OAuth Keys [2024 revised]

If you've stumbled upon my article, I assume you are working on a Django project and are wondering how to secure your project information, more importantly, security keys. If so, you've come to the right place as I am about to teach you the best method of doing it.

More often than not, I see many of my software engineer friends miss a couple of key points when developing Django projects, and that is, not hiding their SECRET_KEY and other OAuth keys. This is a crucial part of the security of Django as any information exposed can revoke a project.

Let's begin. Suppose we have just started a brand new Django project. Just in case, here is the format:

django-admin startproject project
Enter fullscreen mode Exit fullscreen mode

Now that we have created a new project, let's navigate into the root directory, that being project/, and into the settings.py file.

On the 23rd line of the code, you will find a variable titled SECRET_KEY.

import os

# Build paths inside the project like this: os.path.join(BASE_DIR, ...)
BASE_DIR = os.path.dirname...

# SECURITY WARNING: keep the secret key used in production secret!
SECRET_KEY = 'ek0@9u(zemu^+%*-z3!&y9mu_7u+edg9%)c%423mdoec-mi*'
Enter fullscreen mode Exit fullscreen mode

Here we see that, for the purpose of this blog post, my Django security key is exposed.

Now, I will introduce to you a method that will ensure you never expose your project's private keys ever again, dotenv.

In your project terminal, type

pip3 install python-dotenv
Enter fullscreen mode Exit fullscreen mode

This will install a dotenv requirement that will be used to retrieve your secret keys from a file only you have access to.

Next, in your settings.py file, C & V (copy and paste) the following two lines:

from dotenv import load_dotenv
load_dotenv()
Enter fullscreen mode Exit fullscreen mode

Afterward, in the root of your project, create a file titled .env which will serve as your environment variable secret storage for your project.

In the .env, you will declare your variables with an = sign and paste their information as such:

# .env
SECRET_KEY=ek0@9u(zemu^+%*-z3!&y9mu_7u+edg9%)c%423mdoec-mi*
Enter fullscreen mode Exit fullscreen mode

Next, in your settings.py, you will retrieve the key as follows:

# settings.py
SECRET_KEY = str(os.getenv('SECRET_KEY'))
Enter fullscreen mode Exit fullscreen mode

What this line does is make the os (operating system) get the .env file and bring in the data for the following key: SECRET_KEY.

To ensure no one receives access to the .env file, it is a general protocol to put your .env file in the .gitignore to make sure it won't be committed to GitHub.

If you were using any other keys, such as OAuth keys, the method would work the same. For example, here I will implement an OAuth key to use the Twitter OAuth method.

# settings.py
TWITTER_OAUTH_KEY = str(os.getenv('TWITTER_OAUTH_KEY'))
Enter fullscreen mode Exit fullscreen mode

and retrieve the key from my environment file,

# .env
TWITTER_OAUTH_KEY=[twitter-oauth-key-here]
Enter fullscreen mode Exit fullscreen mode

If you would like to follow my software engineering path, feel free to follow me on GitHub.

Top comments (21)

Collapse
 
mattschwartz profile image
Matthew Schwartz

Good tip. My solution is to commit a settings_base.py file with the Django project. On each deployed system (including local) I then have a settings.py file which imports the base file and overrides anything secret or unique to the system.

Your solution is also very convenient when working with docker. It's common practice to pass settings into containers using environment variables.

Collapse
 
vladyslavnua profile image
vladyslav nykoliuk

That's also a very viable solution. Thank you for the comment!

Collapse
 
quroom profile image
quroom • Edited

If you want to set default value, you can use like

SECRET_KEY = os.environ.get('DJANGO_SECRET_KEY', 'DEFAULT_KEY')

DEBUG = bool( os.environ.get('DJANGO_DEBUG', True) )

Then you don't need more settings for production and development.
Just on and off

load_dotenv()

Collapse
 
vladyslavnua profile image
vladyslav nykoliuk

That's pretty clever, I'll be sure to keep it in mind for my next project

Collapse
 
quroom profile image
quroom

I referenced it from mdn ;)
Have a nice day.

Thread Thread
 
vladyslavnua profile image
vladyslav nykoliuk

pretty cool either way. thank you, and likewise!

Collapse
 
codebyline profile image
Yumei Leventhal

Hi there, I joined this forum just to ask this question :-) about this fantastic tip in this post:

My question relates to adding the .env file into .gitignore. How can an app run without the SECRET coming along in production? I read somewhere that a new .env file needs to be created on the production site. In that case, what's the difference between uploading the .env along with the rest of the app and creating a new .env file? Is the concern mostly over the security during uploading?

Collapse
 
vladyslavnua profile image
vladyslav nykoliuk

Thanks for your comment and welcome to Dev! So from my understanding, you already have a .env file in your development server. If that .env file works for you in development, keep that since it will most likely work for production as well. Any time I develop anything for production, I try to keep the .env consistent and hidden in the .gitignore. There shouldn't be any difference between uploading the development .env for production, as long as Django knows where to find your .env.

The biggest security concern that will come up in regards to the environment secrets is accidentally committing them to Github. Let me know if that clears up your question.

Happy Coding!

Collapse
 
codebyline profile image
Yumei Leventhal

Yes, this totally cleared up the fog on my end: Exposing the .env on GitHub is a security risk (as opposed to having .env on a server). Thank you for taking the time to explain! And yes, I followed the steps in this post and everything works beautifully. Since I read your post and became aware of the issue of protecting Django secret, I've read other posts on how to do it-but none is as clean and easy to follow. So thank you for bringing this issue to the attention of new Django learners.

Thread Thread
 
vladyslavnua profile image
vladyslav nykoliuk

It is absolutely my pleasure! So glad it helped :)

Collapse
 
jakemulhern profile image
Jake Mulhern

I followed all of the instructions and copy and pasted everything but I get the error ModuleNotFoundError: No module named 'dotenv'. Any idea why this might be?

Collapse
 
vladyslavnua profile image
vladyslav nykoliuk

Hey! Thanks for your comment. One possibility might be you didn't install the module, which can be done with pip3 install python-dotenv. Another possibility, if you already installed the module, your requirements might not have been updated yet which can be done with pip3 freeze > requirements.txt

Let me know if you continue receiving the error, hopefully, this helped.

Collapse
 
jakemulhern profile image
Jake Mulhern

I appreciate the response! I installed the module but I think I figured out that I did not install Django correctly in the context of the application and that was causing the issue. I will update with more errors if needed.

Collapse
 
rzeczuchy profile image
rzeczuchy • Edited

This was a really helpful article, thank you! If you write anything else on Django security in the future, I'll definitely give it a read.

Collapse
 
vladyslavnua profile image
vladyslav nykoliuk

Thank you! I really appreciate the feedback πŸ™‚

Collapse
 
hengage profile image
Henry Chizoba • Edited

Great tip. A question.

How do i put my .env file in the gitignore?

Collapse
 
vladyslavnua profile image
vladyslav nykoliuk • Edited

you would just list it plainly as that: .env (unless it's not in the same directory as the gitignore file of course)

# .gitignore
.env
env/
...
Enter fullscreen mode Exit fullscreen mode
Collapse
 
hengage profile image
Henry Chizoba

Ok thanks for your response. I have 2 questions.

First, I can't seem to locate the 'gitignore file' on my django project directory.

Second is, the code:
from dotenv import load_dotenv
load_dotenv()

it brings an error saying "unresolved import 'dotenv' in my problem terminal.

I did install dotenov and correctly too. You might have an answer for me? I'm a beginner with django. Thank you

Thread Thread
 
vladyslavnua profile image
vladyslav nykoliuk

The .gitignore file is one you have to manually create, it doesn't come with the initial Django project directory. Make sure its in the same directory as your manage.py file, along with requirements, etc.

Thread Thread
 
vladyslavnua profile image
vladyslav nykoliuk

For the first one, the .gitignore file doesn't come with the initial Django project - you have to manually create it. Make sure it's in the same directory as the manage.py, requirements, etc.

For the dotenv, do the errors still show up after you run:

pip freeze > requirements.txt

?

Thread Thread
 
hengage profile image
Henry Chizoba

Thank you, i fixed it already. Thanks.