diff --git a/.gitignore b/.gitignore
index dc11f6c92be57b93efb71724b0a88ae85381d3e0..fe6937067db8816b713122602238838f16ab075f 100644
--- a/.gitignore
+++ b/.gitignore
@@ -2,4 +2,5 @@ dist/
 MANIFEST
 build/
 *.egg-info/
-*.eggs/
\ No newline at end of file
+*.eggs/
+venv/
\ No newline at end of file
diff --git a/TheCodeLabs_FlaskUtils/TheCodeLabs_FlaskUtils/auth/SessionLoginWrapper.py b/TheCodeLabs_FlaskUtils/TheCodeLabs_FlaskUtils/auth/SessionLoginWrapper.py
new file mode 100644
index 0000000000000000000000000000000000000000..8a92dc9de21d737599d37def39aec5eacaaac6b5
--- /dev/null
+++ b/TheCodeLabs_FlaskUtils/TheCodeLabs_FlaskUtils/auth/SessionLoginWrapper.py
@@ -0,0 +1,15 @@
+from functools import wraps
+
+from flask import session, redirect, url_for
+
+
+def require_login(func):
+    @wraps(func)
+    def check_token(*args, **kwargs):
+        if 'authorized' not in session:
+            return redirect(url_for('authentication.login'))
+
+        # redirect to requested url
+        return func(*args, **kwargs)
+
+    return check_token
diff --git a/TheCodeLabs_FlaskUtils/TheCodeLabs_FlaskUtils/auth/UsernamePasswordService.py b/TheCodeLabs_FlaskUtils/TheCodeLabs_FlaskUtils/auth/UsernamePasswordService.py
new file mode 100644
index 0000000000000000000000000000000000000000..93f5787c33bdae1d4907ed11c1001920386fbd6a
--- /dev/null
+++ b/TheCodeLabs_FlaskUtils/TheCodeLabs_FlaskUtils/auth/UsernamePasswordService.py
@@ -0,0 +1,17 @@
+import bcrypt
+
+
+class UserService:
+    def __init__(self, users):
+        self.__users = {}
+        for user in users:
+            self.__users[user["name"].lower()] = user["password"]
+
+    def get_users(self):
+        return self.__users
+
+    def is_password_valid(self, name: str, password: str) -> bool:
+        saved_password = self.__users.get(name.lower(), None)
+        if saved_password is None:
+            raise ValueError(f'User {name} not found')
+        return bcrypt.checkpw(password.encode(), saved_password.encode())
diff --git a/TheCodeLabs_FlaskUtils/setup.py b/TheCodeLabs_FlaskUtils/setup.py
index a4c021d6dd5dd09682f26f3d8ac93897939e06b2..f94711b0f4333cd790b619582905c394f81d65e3 100644
--- a/TheCodeLabs_FlaskUtils/setup.py
+++ b/TheCodeLabs_FlaskUtils/setup.py
@@ -14,6 +14,7 @@ setup(
     install_requires=[
         'flask',
         'gevent'
+        'bcrypt'
     ],
     setup_requires=[
         'wheel'