Basic Authentication in Password Manager using Tkinter
Tags: programming, python, tkinter, gui
Published: 2021-11-02 17:44:35

---
title: Basic Authentication in Password Manager using Tkinter
published: true
date: 2021-11-02 17:37:12 UTC
series: Password Manager using Tkinter
tags: Programming, Python, Tkinter, GUI
canonical_url: http://iread.ga/posts/62/basic-authentication-in-password-manager-using-tkinter
---
![Thumbnail](https://res.cloudinary.com/dlomjljb6/image/upload/v1/media/blog/thumbnails/manager_1_bv2q32)

This is the second part of the [**Password Manager using Tkinter**](https://iread.ga/series/9/password-manager-using-tkinter) series where we are going to build a Password Manager using Tkinter which will help us manage our passwords easily. Since this will be a _Graphical User Interface(GUI)_ application, it doesn't rely on any kind of web connection. So, let's see what libraries and concepts we are going to use in this application:

- [tkinter module](https://docs.python.org/3/library/tkinter.html)
- [hashlib module](https://docs.python.org/3/library/hashlib.html)
- [sqlite3 module](https://docs.python.org/3/library/sqlite3.html)
- [Python classes](https://docs.python.org/3/tutorial/classes.html)

The basic workflow of the application will be as follows:

- The user opens the application
- If a master password is already present in the database, i.e., the user is already registered, ask the user to log in.
- If no master password is there, ask the user to create a master password and then ask him to log in.
- After login, the user has two options, one to Generate password and another button to add a new password.
- Whenever a password is added, it has three options - Update Password, Copy Password and Delete Password.

So, let's jump into the coding part now.  
 

# **Managing Database**

Since we'll be storing the user's master password and other passwords, we'll be using an SQLite database. The basic idea is, whenever the application is opened, we check if the corresponding databases are already present or not. In case they're not, they are created. Let's create a `database.py` file and add the following code:

```py
import sqlite3

def init_database():
    with sqlite3.connect("password_vault.db") as db:
        cursor = db.cursor()
    cursor.execute("""
            CREATE TABLE IF NOT EXISTS master(
            id INTEGER PRIMARY KEY,
            password TEXT NOT NULL);
            """)

    cursor.execute("""
            CREATE TABLE IF NOT EXISTS vault(
            id INTEGER PRIMARY KEY,
            platform TEXT NOT NULL,
            userid TEXT NOT NULL,
            password TEXT NOT NULL);
            """)
    return db, cursor

```

The reason we're using SQLite database is that it is a **disk-based database** and **doesn't require a separate database server to be running**. We'll be using the in-built Python module [sqlite3](https://docs.python.org/3/library/sqlite3.html) to interact with the database.

In the above script, we have created a `init_database()` function. Inside the function, we are connecting to the `password_vault.db` database using `sqlite3.connect()` method. Note that, if the database is not present, it is automatically created. Further, we are using the `db.cursor()` method that returns an object of the _Cursor_ class, which we'll call cursor. Next, we are executing SQL queries using the `cursor.execute()` method to create two tables - **master** and **vault** , if they don't exist.

```sql
CREATE TABLE IF NOT EXISTS master(
id INTEGER PRIMARY KEY,
password TEXT NOT NULL);
```

The above query creates a table called master having two fields, an integer  **id** (a primary key) and a text  **password**  which should not be null.

```sql
CREATE TABLE IF NOT EXISTS vault(
id INTEGER PRIMARY KEY,
platform TEXT NOT NULL,
userid TEXT NOT NULL,
password TEXT NOT NULL);
```

The above command will create a table called vault having four fields - an integer  **id** (a primary key), a text **platform** to store the website or app name, a text **userid** to store the email or username, and a text  **password**  that should not be null.

After these commands are executed, we return the `db` and `cursor` to be used by other classes and methods.  
 

# **Password Manager Class**

We'll be creating a _PasswordManager_ class in a Python file `manager.py` that will have the following components:

1. Welcome New User
2. Login User
3. Password Vault Screen

Let us start by first creating the constructor for the _PasswordManager _class.

```py
from database import init_database
from tkinter import Tk

class PasswordManager:

    def __init__ (self):
        self.db, self.cursor = init_database()
        self.window = Tk()
        self.window.update()
        self.window.title("Password Manager")
        self.window.geometry("650x350")
```

The above script is pretty simple where were are first initializing the database using the function we created in the previous section. Next, we are creating a window of size **650x350** with the title **Password Manager**.  
 

### **Utility Methods**

We'll be using two utility methods - one to encrypt password and other to copy text. Let's create them one by one:

```py
import hashlib

def encrypt_password(self, password):
    password = password.encode("utf-8")
    encoded_text = hashlib.md5(password).hexdigest()
    return encoded_text
```

We are using hashlib module to encrypt our passwords. We're using the **md5** hashing algorithm. This hash function splits the string into equal parts and then computes a 128-bit hash value of the entire string through chaining. The `hexdigest()` method returns the encoded text as a string.

```py
def copy_text(self, text):
    self.window.clipboard_clear()
    self.window.clipboard_append(text)
```

First, we are clearing our clipboard so that if anything is already copied, it is erased. Then we are appending the text which is passed as an argument to the `copy_text()` method.  
 

### **1. Welcome New User**

A new user will be welcomed with another window of a different size. This window would just have two labels, and two entry boxes, and a button. The button, when pressed, will call another method to save the password.

```py
from functools import partial
from tkinter import Button, Entry, Label, Tk
from tkinter.constants import CENTER

def welcome_new_user(self):
    self.window.geometry("450x200")

    label1 = Label(self.window, text="Create New Master Password")
    label1.config(anchor=CENTER)
    label1.pack(pady=10)

    mp_entry_box = Entry(self.window, width=20, show="*")
    mp_entry_box.pack()
    mp_entry_box.focus()

    label2 = Label(self.window, text="Enter the password again")
    label2.config(anchor=CENTER)
    label2.pack(pady=10)

    rmp_entry_box = Entry(self.window, width=20, show="*")
    rmp_entry_box.pack()

    self.feedback = Label(self.window)
    self.feedback.pack()

    save_btn = Button(self.window, text="Create Password",
                          command=partial(self.save_master_password, mp_entry_box, rmp_entry_box))
    save_btn.pack(pady=5)
```

As mentioned above, we're first setting the window size to 450x200. We are then creating and packing a label with the text _Create New Master Password_. Next, we are creating and packing an entry box. Since this will be a password field, we have `show="*"` in the entry box object. Similarly, we are creating and packing another label with the text _Enter the password again_ and a password entry box for the user to re-enter the password. Next, we have a save button to create the user. In the command, we are passing a `save_master_password `method and the two entry boxes as arguments using the `partial `function. Additionally, we have a feedback label to show feedback if the two passwords are not the same.

Let's create the method to save the master password:

```py
def save_master_password(self, eb1, eb2):
    password1 = eb1.get()
    password2 = eb2.get()
    if password1 == password2:
        hashed_password = self.encrypt_password(password1)
        insert_command = """INSERT INTO master(password)
        VALUES(?) """
        self.cursor.execute(insert_command, [hashed_password])
        self.db.commit()
        self.login_user()
    else:
        self.feedback.config(text="Passwords do not match", fg="red")
```

In the above script, we're first getting the values from the two password entry boxes using the get() method in the Entry class. If the passwords are not same, we are showing a feedback to the user. If they're same, we first hash the password using the encrypt\_password() method that we've created above. Then we have a SQL query to insert the hashed password into the master table. We execute the command and commit the session, and then ask the user to log in. We'll be creating this method next.

![](https://res.cloudinary.com/dlomjljb6/image/upload/v1/media/blog/uploads/2021/11/02/screenshot-2021-11-02-220809_cv8bvt)

![](https://res.cloudinary.com/dlomjljb6/image/upload/v1/media/blog/uploads/2021/11/02/screenshot-2021-11-02-223627_cyaihi)  
 

### **2. Login User**

In this window, we'll have just two labels, one entry box and a button. 

```py
def login_user(self):
    for widget in self.window.winfo_children():
        widget.destroy()

    self.window.geometry("450x200")

    label1 = Label(self.window, text="Enter your master password")
    label1.config(anchor=CENTER)
    label1.place(x=150, y=50)

    self.password_entry_box = Entry(self.window, width=20, show="*")
    self.password_entry_box.place(x=160, y=80)
    self.password_entry_box.focus()

    self.feedback = Label(self.window)
    self.feedback.place(x=170, y=105)

    login_btn = Button(self.window, text="Log In", command=partial(
            self.check_master_password, self.password_entry_box))
    login_btn.place(x=200, y=130)
```

First, we are destroying all the children of the current window and setting the current window size to 450x200. Then as we did in the welcome user section, we are creating a label and a password entry box for the user to enter the password. A feedback label is also there to show an error message if the password is wrong. The button this time will have `check_master_password `method in the command with the password entry box as the argument.

Let's create this check\_master\_password method:

```py
def check_master_password(self, eb):
    hashed_password = self.encrypt_password(eb.get())
    self.cursor.execute(
            "SELECT * FROM master WHERE id = 1 AND password = ?", [hashed_password])
    if self.cursor.fetchall():
        self.password_vault_screen()
    else:
        self.password_entry_box.delete(0, END)
        self.feedback.config(text="Incorrect password", fg="red")
```

In the above method, we first hash the password value from the entry box using the `encrypt_password()` method. Then we check in the database if there exists any row which has **id=1** and **password=hashed\_password**. The id=1 is there because we're assuming only one person will be using this application. So whenever the user sets his master password, id 1 is assigned to it. We use the `cursor.fetchall()` method to fetch all (remaining) rows of the query result. If we get any result, it means the correct password is entered, and hence we show the password vault screen to the user(we'll create this soon). In case it returns an empty list, we clear the entry box and add the error message in the feedback label.

![](https://res.cloudinary.com/dlomjljb6/image/upload/v1/media/blog/uploads/2021/11/02/screenshot-2021-11-02-224201_hl7og9)

![](https://res.cloudinary.com/dlomjljb6/image/upload/v1/media/blog/uploads/2021/11/02/screenshot-2021-11-02-224233_kijn9e)  
 

### **3. Password Vault Screen**

This is the main screen of the application where users will be able to add new passwords, modify previously saved passwords, delete passwords and copy passwords.  
 

# **Conclusion**

We're not going to see the Password Vault Screen in this part, else the post will be too long. In the next part of the series, we'll continue right from here and end this series. In this part, we covered the basic authentication part of the application. Stay tuned for the next part!