diff --git a/.vscode/launch.json b/.vscode/launch.json
index 68bf174870fd950031c7088641521fd2edbab836..a2e884a29372cd113a7dfff98c62a007d4fc1bce 100644
--- a/.vscode/launch.json
+++ b/.vscode/launch.json
@@ -19,7 +19,8 @@
                 "--no-reload"
             ],
             "jinja": true,
-            "autoStartBrowser": false
+            "autoStartBrowser": false,
+            "preLaunchTask": "Install Requirements"
         }
     ]
 }
\ No newline at end of file
diff --git a/.vscode/tasks.json b/.vscode/tasks.json
new file mode 100644
index 0000000000000000000000000000000000000000..7ba19183135e479bfc420a96ae151876f18105dc
--- /dev/null
+++ b/.vscode/tasks.json
@@ -0,0 +1,11 @@
+{
+    "version": "2.0.0",
+    "tasks": [
+        {
+            "label": "Install Requirements",
+            "type": "shell",
+            "command": "pip install -r requirements.txt",
+            "problemMatcher": []
+        }
+    ]
+}
diff --git a/app/__init__.py b/app/__init__.py
index 35b1be553b2454c1b9b997b2c47b3446cd68c444..db209774c40df748848c8536ae1db4a2ec276607 100644
--- a/app/__init__.py
+++ b/app/__init__.py
@@ -6,11 +6,13 @@ from flask_sqlalchemy import SQLAlchemy
 from flask_migrate import Migrate
 from flask_login import LoginManager, current_user
 from dotenv import load_dotenv
+from flask_wtf.csrf import CSRFProtect
 import os
 
 db = SQLAlchemy()
 migrate = Migrate()
 login_manager = LoginManager()
+csrf = CSRFProtect()
 
 def create_app(config_class=Config):    
     app = Flask(__name__)
@@ -40,6 +42,9 @@ def create_app(config_class=Config):
 
     # Register blueprints and url prefixes
     register_blueprints(app)
+
+    #Protect internal endpoints from external use
+    csrf.init_app(app)
     
     # Add any vars needed accessible through all templates
     @app.context_processor
diff --git a/app/api/routes.py b/app/api/routes.py
index 503853e56491a02df325c73afb31916631fe5157..1c40f57de07b90beaedd98c2b7f704215d5163bb 100644
--- a/app/api/routes.py
+++ b/app/api/routes.py
@@ -2,6 +2,7 @@ from flask import render_template, redirect, url_for, Flask, jsonify
 from app.api import bp
 from app.models import User, Listings
 from sqlalchemy import text
+from app import csrf
 
 @bp.route('/user_id/<int:id>', methods=['GET'])
 def get_user_by_id(id):
diff --git a/app/models/user.py b/app/models/user.py
index dcc99b3c7ee8e9a4e1a30e9708f35af1ee4d6b66..fd813cc96e0cff9220df2ced7d4a74f8e9eb5446 100644
--- a/app/models/user.py
+++ b/app/models/user.py
@@ -31,4 +31,10 @@ class User(UserMixin, db.Model):
     def search_user_by_email(cls, user_email):
         user_exist = cls.query.filter_by(email=user_email).first()
         
+        return user_exist
+    
+    @classmethod
+    def search_user_by_username(cls, user_name):
+        user_exist = cls.query.filter_by(username=user_name).first()
+        
         return user_exist
\ No newline at end of file
diff --git a/app/profile/routes.py b/app/profile/routes.py
index 63f67bb4963029ffbb8c60a8ca4a528de1c7d8bd..223415e105122a98c50398e40f94ea4469449dec 100644
--- a/app/profile/routes.py
+++ b/app/profile/routes.py
@@ -1,5 +1,5 @@
 #https://www.digitalocean.com/community/tutorials/how-to-add-authentication-to-your-app-with-flask-login#step-1-installing-packages
-from flask import Blueprint, render_template, redirect, url_for, request, flash
+from flask import Blueprint, render_template, redirect, url_for, request, flash, jsonify
 from app.profile import bp
 from werkzeug.security import check_password_hash
 from app.models import User
@@ -7,39 +7,39 @@ from app import db
 from flask_login import login_user, logout_user, login_required, current_user
 from app.logger import auth_logger
 
-@bp.route('/signup')
+@bp.route('/signup', methods=['GET', 'POST'])
 def signup():
-    return render_template('profile/signup.html')
+    if request.method == 'POST':
+        form_data = {
+            'email': request.form.get('email'),
+            'username': request.form.get('username'),
+            'password': request.form.get('password')
+        }
 
-@bp.route('/signup', methods=['POST'])
-def signup_post():
-    form_data = {
-        'email': request.form.get('email'),
-        'username': request.form.get('username'),
-        'password': request.form.get('password')
-    }
+        if not form_data['username'] or not form_data['email'] or not form_data['password']:
+            flash('Missing required fields: Email, Username, Password')
+            return redirect(url_for('profile.signup'))
 
-    user = User.query.filter_by(email=form_data['email']).first()
+        user = User.query.filter_by(email=form_data['email']).first()
 
-    if user:
-        return redirect(url_for('profile.signup'))
+        if user:
+            flash('Email address already exists')
+            return redirect(url_for('profile.signup'))
 
-    try:
-        if not form_data['username'] or not form_data['email'] or not form_data['password']:
-            raise ValueError("Missing required fields: Email, Username, Password")
-        new_user = User.create_user(username=form_data['username'], email=form_data['email'], password=form_data['password'])
-    except ValueError as e:
-        auth_logger.error("Unable to create user, full error was: " + str(e))
-        flash('Missing required fields')
-        return redirect(url_for('profile.signup'))
+        try:
+            new_user = User.create_user(username=form_data['username'], email=form_data['email'], password=form_data['password'])
+            db.session.add(new_user)
+            db.session.commit()
 
-    db.session.add(new_user)
-    db.session.commit()
+            login_user(new_user)
+            return redirect(url_for('profile.index'))
+        except Exception as e:
+            auth_logger.error(f"Unable to create user: {e}")
+            flash('An error occurred. Please try again.')
+            return redirect(url_for('profile.signup'))
 
-    # Log the user in automatically 
-    login_user(new_user) 
+    return render_template('profile/signup.html')
 
-    return redirect(url_for('profile.index'))
 
 @bp.route('/login', methods=['POST'])
 def login_post():
@@ -56,6 +56,34 @@ def login_post():
     login_user(user, remember=remember)
     return redirect(url_for('profile.index'))
 
+
+@bp.route('/check-username', methods=['POST'])
+def check_username():
+    data = request.get_json()
+    username = data.get('username', '').strip()
+    if username is None:
+        return jsonify({'error': 'Username is required'}), 400
+    
+    #Search to see if username already exists
+    user_exist = User.search_user_by_username(username)
+    if user_exist is not None:
+        return jsonify({'error': 'Username already exists'}), 400
+
+    return jsonify({'available': True, 'success': username + 'is available.'})
+
+
+@bp.route('/check-email', methods=['POST'])
+def check_email():
+    data = request.get_json()
+    email = data.get('email', '').strip()
+    
+    if not email:
+        return jsonify({'error': 'Email is required'}), 400
+
+    is_available = email not in emails
+    return jsonify({'available': is_available})
+
+
 @bp.route('/logout')
 @login_required
 def logout():
@@ -64,6 +92,8 @@ def logout():
 
 @bp.route('/login')
 def login():
+    if current_user.is_authenticated:
+        return redirect(url_for('profile.index'))
     return render_template('profile/login.html')
 
 @login_required
diff --git a/app/static/base.css b/app/static/base.css
index 008b2e0d62339674cb5aa2f197002e7fe1a499ab..b19ba9383e24e6bd0875b5971ab4384681074ce2 100644
--- a/app/static/base.css
+++ b/app/static/base.css
@@ -89,25 +89,23 @@ Form styling options
 .form_box_30 {
     position: relative;
     width: 100%; 
-    max-width: 400px; /* Maximum width for larger screens */
+    max-width: 400px;
     margin: auto;
     vertical-align: middle;
-    padding: 15px; /* Add some padding */
+    padding: 15px;
 }
 
 @media (max-width: 600px) {
     .form_box_30 {
-        width: 90%; /* Adjust width for smaller screens */
+        width: 90%;
     }
 }
 
-
-.background_1 {
+.profile_form_background {
     border-radius: 25px;
-    background: #90AEAD;
+    background: #244855;
     padding: 50px;
     color: #FBE9D0; 
-    background-image: linear-gradient(to bottom right, #4169e1, #89CFF0);
 }
 
 .form-check-input:checked {
@@ -115,6 +113,16 @@ Form styling options
     background: #FBE9D0;
 }
 
+.form_header {
+    text-align: center;
+    text-transform: uppercase;
+    margin-bottom: 20px;
+}
+
+.username-feedback .email-feedback {
+    text-align: center;
+}
+
 /* HEX codes for colours used through out website don't delete */
 
 /* Colour pallete taken from https://visme.co/blog/website-color-schemes/
diff --git a/app/static/navigation.js b/app/static/generic.js
similarity index 100%
rename from app/static/navigation.js
rename to app/static/generic.js
diff --git a/app/templates/base.html b/app/templates/base.html
index 0864006d2b0324c008546a8f02c87d54c9061f21..f1586d9b504371930c5a7e783508c58aa2eb5756 100644
--- a/app/templates/base.html
+++ b/app/templates/base.html
@@ -2,7 +2,9 @@
 <!DOCTYPE html>
 <html>
     <head>
+        <meta name="csrf-token" content="{{ csrf_token() }}">
         <link rel="stylesheet" type="text/css" href="{{ url_for('static', filename='base.css')}}">
+        <link rel="stylesheet" href="{{ url_for('static', filename='generic.js')}}">
         <link href="https://cdn.jsdelivr.net/npm/bootstrap@5.1.3/dist/css/bootstrap.min.css" rel="stylesheet" integrity="sha384-1BmE4kWBq78iYhFldvKuhfTAU6auU8tT94WrHftjDbrCEXSU1oBoqyl2QvZ6jIW3" crossorigin="anonymous">
         <script src="https://cdn.jsdelivr.net/npm/bootstrap@5.1.3/dist/js/bootstrap.bundle.min.js" integrity="sha384-ka7Sk0Gln4gmtz2MlQnikT1wXgYsOg+OMhuP+IlRH9sENBO0LRn5q+8nbTov4+1p" crossorigin="anonymous"></script>
         <link rel="stylesheet" type="text/css" href="{{ url_for('static', filename='bootstrap_overrides.css')}}">
diff --git a/app/templates/profile/login.html b/app/templates/profile/login.html
index 130d7ef05531ea889a4da4f1c931e4406cfef4b3..0f6d9a0b9e706e896ba870ad359b8fe635ec8746 100644
--- a/app/templates/profile/login.html
+++ b/app/templates/profile/login.html
@@ -1,10 +1,11 @@
 {% extends 'base.html' %}
 {% block content %}
 <div class="column is-4 is-offset-4">
-    <div id="login-box" class="form_box_30">
-        <h3 style="margin-top:30px; text-align:center">Login</h3>
-        <div class="background_1">
+    <div id="login-box" class="form_box_30" style="margin-top: 30px;">
+        <div class="profile_form_background">
+            <h2 class="form_header">Login</h2>
             <form method="POST" action="{{ url_for('profile.login_post') }}">
+                {{ csrf_token() }}
                 <div class="mb-3">
                     <label class="form-label" autofocus="">Username</label>
                     <input type="text" class="form-control" name="username">
@@ -26,4 +27,4 @@
         </div>
     </div>
 </div>
-{% endblock %}
\ No newline at end of file
+{% endblock %}
diff --git a/app/templates/profile/signup.html b/app/templates/profile/signup.html
index a7ef4e83f04fd94c80ebb7a1ea37f26cb82dfaaf..24849007116bf863f9c3d6018aa9a2a0a6947cfe 100644
--- a/app/templates/profile/signup.html
+++ b/app/templates/profile/signup.html
@@ -1,27 +1,82 @@
 {% extends 'base.html' %}
 
 {% block content %}
-    <div class="form_box_30 background_1">
-        <h3 style="margin-top:30px">Sign Up</h3>
-        <form method="POST" action="{{ url_for('profile.signup_post') }}">
+<div class="form_box_30 background_1">
+    <div class="profile_form_background">
+        <h3 class="form_header">Sign Up</h3>
+        <form method="POST" action="{{ url_for('profile.signup') }}">
+            <input type="hidden" name="csrf_token" value="{{ csrf_token() }}">
             <div class="mb-3">
-                <label class="form-label" autofocus="">Username</label>
-                <input type="username" class="form-control" name="username">
+                <label class="form-label" for="username" autofocus="">Username</label>
+                <input type="text" id="username" class="form-control" name="username" required>
+                <small id="username-feedback" class="form-text"></small>
             </div>
             <div class="mb-3">
-                <label class="form-label">Email address</label>
-                <input type="email" class="form-control" name="email">
+                <label class="form-label" for="email">Email address</label>
+                <input type="email" id="email" class="form-control" name="email" required>
+                <small id="email-feedback" class="form-text"></small>
             </div>
             <div class="mb-3">
-                <label class="form-label">Password</label>
-                <input type="password" class="form-control" name="password">
+                <label class="form-label" for="password">Password</label>
+                <input type="password" id="password" class="form-control" name="password" required>
             </div>
             <div class="mb-3 form-check">
                 <input type="checkbox" class="form-check-input" id="remember" name="remember">
                 <label class="form-check-label" for="remember">Remember me</label>
             </div>
-            <button type="submit" class="btn btn-primary">Log In</button>
-            </form>
+            <button type="submit" class="btn btn-primary">Sign Up</button>
+        </form>
     </div>
+</div>
 
-{% endblock %}
\ No newline at end of file
+<script>
+    function makeAjaxRequest(url, data, field) {
+        const feedbackElement = document.getElementById(`${field}-feedback`);
+        const csrfToken = document.querySelector('meta[name="csrf-token"]').getAttribute('content');
+
+        feedbackElement.textContent = '';
+        feedbackElement.style.color = '';
+
+        if (data[field].length > 0) {
+            fetch(url, {
+                method: 'POST',
+                headers: {
+                    'X-CSRFToken': csrfToken,
+                    'Content-Type': 'application/json',
+                },
+                body: JSON.stringify(data),
+            })
+                .then(response => response.json())
+                .then(data => {
+                    if (data.available) {
+                        feedbackElement.textContent = `${field.charAt(0).toUpperCase() + field.slice(1)} is available.`;
+                        feedbackElement.style.color = 'green';
+                    } else {
+                        feedbackElement.textContent = `${field.charAt(0).toUpperCase() + field.slice(1)} is already taken.`;
+                        feedbackElement.style.color = 'red';
+                    }
+                })
+                .catch(error => {
+                    feedbackElement.textContent = `Error checking ${field}.`;
+                    feedbackElement.style.color = 'red';
+                });
+        }
+    }
+
+    function checkUsernameAvailability(username) {
+        makeAjaxRequest("{{ url_for('profile.check_username') }}", { 'username': username }, 'username');
+    }
+
+    function checkEmailAvailability(email) {
+        makeAjaxRequest("{{ url_for('profile.check_email') }}", { 'email': email }, 'email');
+    }
+
+    document.getElementById('username').addEventListener('blur', function () {
+        checkUsernameAvailability(this.value);
+    });
+
+    document.getElementById('email').addEventListener('blur', function () {
+        checkEmailAvailability(this.value);
+    });
+</script>
+{% endblock %}
diff --git a/requirements.txt b/requirements.txt
index 619304637acfffb56b3620f7b5474dc948294fc8..eebb30e827ff7a6a96ee58cf463372a60942ccb4 100644
--- a/requirements.txt
+++ b/requirements.txt
@@ -6,4 +6,5 @@ python-dotenv
 jinja2
 cryptography
 flask-login
-debugpy
\ No newline at end of file
+debugpy
+flask-wtf
\ No newline at end of file