How to Create a Password Manager using Python GUI

TKinter, Python’s de facto standard GUI

Huixin K.
3 min readDec 14, 2020

Motivation

I used to have a single password for everything until I learnt things the hard way. So I started creating more complicated passwords and my caveman instinct taught me to save them somewhere. Before you opine whether storing non-encrypted passwords locally is a heinous crime, please know that I’m still going to proceed with this post.

Starting with the end in mind

Building the UI

This is the easy part.

root = Tk()
root.title(“Password Manager”)
root.config(padx=50, pady=50, bg=NAVY)
# insert widgets hereroot.mainloop()

Canvas widget

# ROW 0
canvas = Canvas(height=200, width=200, bg=NAVY, highlightthickness=0)
img = PhotoImage(file='logo.png')
canvas.create_image(100, 100, image=img)
canvas.grid(row=0,column=1)

Other widgets

What is worth noting in the below code is that it’s not such a great idea to hardcode the widget width because there’s too much trial and error. A better way would be to use the sticky parameter.

Notice that there are 3 button widgets linked to search_website, random_password and saved_entries using thecommand param which we will build in the later section.

# ROW 1
website_label = Label(text=’Website:’, bg=NAVY, fg=BEIGE)
website_label.grid(row=1,column=0,sticky=”W”)
website_entry = Entry()
website_entry.grid(row=1,column=1, columnspan=2,sticky=”EW”)
website_entry.focus()
website_search = Button(text='Search', bg=GREY, command=search_website)
website_search.grid(row=1,column=2,sticky="EW")
# ROW 2
email_label = Label(text=’Email/Username:’, bg=NAVY, fg=BEIGE)
email_label.grid(row=2,column=0,sticky=”W”)
email_entry = Entry()
email_entry.grid(row=2,column=1, columnspan=2,sticky=”EW”)
email_entry.insert(0, ‘myusername@gmail.com’)
# ROW 3
password_label = Label(text=’Password:’, bg=NAVY, fg=BEIGE)
password_label.grid(row=3,column=0,sticky=”W”)
password_entry = Entry()
password_entry.grid(row=3,column=1,sticky=”EW”)
password_button = Button(text=’Generate Password’, bg=GREY, command=random_password)
password_button.grid(row=3,column=2,sticky=”EW”)
# ROW 4
button = Button(text=’Add’, bg=GREY, command=saved_entries)
button.grid(row=4,column=1,columnspan=2,sticky=”EW”)
button.config(pady=2)

Creating function to save into output file

We start off by collecting the user inputs before serializing into a specifc json format.

def saved_entries():# GETTING THE USER INPUTS
user_website = website_entry.get()
user_email = email_entry.get()
user_password = password_entry.get()
new_data = {
user_website: {
'email': user_email,
'password': user_password
}
}
...

Before we save the entry into our json file, it’d be wise to confirm if there are any blank fields or typos. Hence we imported the messagebox module which is basically just a window pop-up.

Here’s a link to working with json data namely json.load(), json.update() and json.dump()

def saved_entries():    if len(user_website) != 0 and len(user_password) != 0:        try:
## LOADING JSON FILE IF EXIST
with open('data.json', 'r') as data_file:
data = json.load(data_file)
data.update(new_data)

except FileNotFoundError:
## CREATE JSON FILE AND CREATE FIRST ENTRY IF DONT EXIST
with open('data.json','w') as data_file:
json.dump(new_data, data_file, indent=4)

else:
## CONFIRM DETAILS BEFORE DUMPING INTO JSON FILE
is_correct = messagebox.askyesno(
title=f"{user_website}",
message=f"\n'email': {user_email}\n
'password': {user_password}\n\n
Please confirm before saving!")
if is_correct:
with open('data.json','w') as data_file:
json.dump(data, data_file, indent=4)
website_entry.delete(0, END)
password_entry.delete(0, END)
else:
# IF WEBSITE OR EMAIL ENTRY IS BLANK
messagebox.showwarning(
title='Oops',
message="Please don't leave any fields empty!"
)

Creating function to generate a random password

The last function is probably the easiest one. The only tkinter-ish thing to highlight here is knowing how to work with Entry, particularly delete and insert.

For better user experience, the generated password is also auto-saved onto the clipboard using pyperclip module.

Side note: “how to apply a function to every item in a list” is something I often googled

def random_password():letters = list(‘ABCDEFGHIJKLMNOPQRSTUVWXYZ’)
numbers = list(‘0123456789’)
symbols = list(‘!@#$%^&*()_+’)
letters_lower = list(map(str.lower,letters))
letters.extend(letters_lower)
#Return a number between a and b (both included):
num_letters = random.randint(8,10)
num_numbers = random.randint(1,2)
num_symbols = random.randint(1,2)
# Creating password in one big list
rand_letters = [random.choice(letters) for i in range(num_letters)]
rand_numbers = [random.choice(numbers) for i in range(num_numbers)]
rand_symbols = [random.choice(symbols) for i in range(num_symbols)]
created_password = rand_letters + rand_numbers + rand_symbols# Shuffle the positions and join to create str
random.shuffle(created_password)
created_password = ‘’.join(created_password)
# Insert into password_entry label upon clicking “Generate password”
password_entry.delete(0, END)
password_entry.insert(0, created_password)
# Copy created password to clipboard
pyperclip.copy(created_password)

Conclusion

The full code can be found here: https://github.com/hxkoey/passwordmanager-tkinter

--

--