Skip to content

A complete Django authentication system with user registration, login, logout, and secure password reset functionality using session-based authentication and email verification.

Notifications You must be signed in to change notification settings

LinusBwana/Session-Based-Authentication

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

9 Commits
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

Django Session-Based Authentication System

A complete Django authentication system with user registration, login, logout, and password reset functionality using session-based authentication.

Features

  • User Registration with validation
  • User Login/Logout
  • Password Reset via Email
  • Session-based authentication
  • Form validation and error handling
  • Secure password reset with expiration links

Prerequisites

  • Python 3.x
  • Django 4.x or higher
  • Email backend configuration for password reset functionality

Installation & Setup

  1. Clone the repository

    git clone <your-repository-url> cd <project-directory>
  2. Install dependencies

    pip install django
  3. Add the PasswordReset model to your models.py

    from django.db import models from django.contrib.auth.models import User import uuid class PasswordReset(models.Model): user = models.ForeignKey(User, on_delete=models.CASCADE) reset_id = models.UUIDField(default=uuid.uuid4, unique=True, editable=False) created_when = models.DateTimeField(auto_now_add=True) def __str__(self): return f"Password reset for {self.user.username} at {self.created_when}"
  4. Configure email settings in settings.py

    EMAIL_BACKEND = 'django.core.mail.backends.smtp.EmailBackend' EMAIL_HOST = "smtp.gmail.com" EMAIL_PORT = 465 EMAIL_USE_SSL = True EMAIL_HOST_USER = "email@gmail.com" EMAIL_HOST_PASSWORD = "google app password"
  5. Create and run migrations

    python manage.py makemigrations python manage.py migrate
  6. Start the development server

    python manage.py runserver

File Structure

your_app/ ├── models.py # PasswordReset model ├── views.py # Authentication views ├── urls.py # URL patterns └── templates/ ├── index.html # Home page ├── register.html # Registration form ├── login.html # Login form ├── forgot_password.html # Forgot password form ├── password_reset_sent.html # Reset email sent confirmation └── reset_password.html # Password reset form 

Models

PasswordReset Model

class PasswordReset(models.Model): user = models.ForeignKey(User, on_delete=models.CASCADE) reset_id = models.UUIDField(default=uuid.uuid4, unique=True, editable=False) created_when = models.DateTimeField(auto_now_add=True)
  • Links to Django's built-in User model
  • Uses UUID for secure reset tokens
  • Tracks creation time for expiration validation

URL Patterns

urlpatterns = [ path('', views.home, name='home'), path('register/', views.registerView, name='register'), path('login/', views.loginView, name='login'), path('logout/', views.logoutView, name='logout'), path('forgot-password/', views.forgotPassword, name='forgot-password'), path('password-reset-sent/<str:reset_id>/', views.passwordResetSent, name='password-reset-sent'), path('reset-password/<str:reset_id>/', views.resetPassword, name='reset-password'), ]

Views Code Overview

Home View (Protected Route)

@login_required def home(request): return render(request, 'index.html')

This view requires user authentication and serves as the main dashboard after login.

1. User Registration (/register/)

Process:

  1. User fills out registration form with:

    • First name
    • Last name
    • Username
    • Email
    • Password
    • Confirm password
  2. Server-side validation:

    • Checks if username already exists
    • Checks if email already exists
    • Validates password length (minimum 8 characters)
    • Confirms password match
  3. On success:

    • Creates new user account
    • Redirects to login page with success message
  4. On error:

    • Displays appropriate error messages
    • Redirects back to registration form

Code Implementation:

def registerView(request): if request.method == "POST": first_name = request.POST.get('first_name') last_name = request.POST.get('last_name') username = request.POST.get('username') email = request.POST.get('email') password = request.POST.get('password') confirm_password = request.POST.get('confirm_password') user_data_has_error = False # checking whether email and username are not being used if User.objects.filter(username=username).exists(): user_data_has_error = True messages.error(request, 'Username already exists') if User.objects.filter(email=email).exists(): user_data_has_error = True messages.error(request, 'Email already exists') if len(password) < 8: user_data_has_error = True messages.error(request, 'Password must be at least 8 characters') if (password != confirm_password): user_data_has_error = True messages.error(request, 'Passwords do not match') if not user_data_has_error: new_user = User.objects.create_user( first_name = first_name, last_name = last_name, email = email, username = username, password = password ) messages.success(request, 'Account created. Login now') return redirect('login') return redirect('register') return render(request, 'register.html')

2. User Login (/login/)

Process:

  1. User enters username and password
  2. Django authenticates credentials using authenticate()
  3. On success:
    • User session is created using login()
    • Redirects to home page
  4. On failure:
    • Displays "Invalid username or password" error
    • Redirects back to login form

Code Implementation:

def loginView(request): if request.method == "POST": # getting user inputs from frontend username = request.POST.get('username') password = request.POST.get('password') # authenticate credentials user = authenticate(request, username=username, password=password) if user is not None: login(request, user) return redirect('home') messages.error(request, 'Invalid username or password') return redirect('login') return render(request, 'login.html')

3. User Logout (/logout/)

Process:

  1. Calls Django's logout() function
  2. Destroys user session
  3. Redirects to login page

Code Implementation:

def logoutView(request): logout(request) return redirect('login')

4. Forgot Password (/forgot-password/)

Process:

  1. User enters email address
  2. System checks if email exists in database
  3. If email exists:
    • Creates new PasswordReset instance with unique UUID
    • Generates password reset URL
    • Sends email with reset link
    • Redirects to confirmation page
  4. If email doesn't exist:
    • Shows error message
    • Redirects back to forgot password form

Code Implementation:

def forgotPassword(request): if request.method == "POST": email = request.POST.get('email') # verify if email exists try: user = User.objects.get(email=email) # create a new reset id new_password_reset = PasswordReset(user=user) new_password_reset.save() # creating password reset url; password_reset_url = reverse('reset-password', kwargs={'reset_id': new_password_reset.reset_id}) full_password_reset_url = f'{request.scheme}://{request.get_host()}{password_reset_url}' # email content email_body = f'Reset your password using the link below:\n\n\n{full_password_reset_url}' email_message = EmailMessage( 'Reset your password', # email subject email_body, settings.EMAIL_HOST_USER, # email sender [email] # email receiver  ) email_message.fail_silently = True email_message.send() return redirect('password-reset-sent', reset_id=new_password_reset.reset_id) except User.DoesNotExist: messages.error(request, f"No user with email '{email}' found") return redirect('forgot-password') return render(request, 'forgot_password.html')

5. Password Reset Confirmation (/password-reset-sent/<reset_id>/)

Process:

  1. Validates that reset ID exists in database
  2. If valid: Shows confirmation page
  3. If invalid: Redirects to forgot password with error

Code Implementation:

def passwordResetSent(request, reset_id): if PasswordReset.objects.filter(reset_id=reset_id).exists(): return render(request, 'password_reset_sent.html') else: # redirect to forgot password page if code does not exist messages.error(request, 'Invalid reset id') return redirect('forgot-password')

6. Password Reset (/reset-password/<reset_id>/)

Process:

  1. Validates reset ID exists
  2. User enters new password and confirmation
  3. Validation checks:
    • Passwords match
    • Password minimum length (8 characters)
    • Reset link hasn't expired (10-minute window)
  4. On success:
    • Updates user password using set_password()
    • Deletes used reset token
    • Redirects to login with success message
  5. On error:
    • Shows appropriate error messages
    • For expired links: deletes token and redirects to forgot password

Code Implementation:

def resetPassword(request, reset_id): try: password_reset_id = PasswordReset.objects.get(reset_id=reset_id) if request.method == 'POST': password = request.POST.get('password') confirm_password = request.POST.get('confirm_password') passwords_have_error = False if password != confirm_password: passwords_have_error = True messages.error(request, 'Passwords do not match') if len(password) < 8: passwords_have_error = True messages.error(request, 'Password must be at least 8 characters long') # check to make sure link has not expired expiration_time = password_reset_id.created_when + timezone.timedelta(minutes=10) if timezone.now() > expiration_time: passwords_have_error = True messages.error(request, 'Reset link has expired') # delete reset id since it has expired password_reset_id.delete() # reset password if not passwords_have_error: user = password_reset_id.user user.set_password(password) user.save() # delete reset id after use password_reset_id.delete() # redirect to login messages.success(request, 'Password reset. Proceed to login') return redirect('login') else: # redirect back to password reset page and display errors return redirect('reset-password', reset_id=reset_id) except PasswordReset.DoesNotExist: # redirect to forgot password page if code does not exist messages.error(request, 'Invalid reset id') return redirect('forgot-password') return render(request, 'reset_password.html')

Security Features

Password Reset Security

  • Unique UUID tokens: Each reset request generates a unique, non-guessable token
  • Time-based expiration: Reset links expire after 10 minutes
  • One-time use: Tokens are automatically deleted after successful password reset or when expired
  • Email validation: Only registered email addresses can request resets

Form Validation

  • Username uniqueness: Prevents duplicate usernames
  • Email uniqueness: Prevents duplicate email addresses
  • Password strength: Minimum 8-character requirement
  • Password confirmation: Ensures passwords match

Session Security

  • Uses Django's built-in session framework
  • Login required decorator protects authenticated routes
  • Proper logout destroys sessions

Template Requirements

Your templates should include the following forms:

Registration Form (register.html)

<form method="POST"> {% csrf_token %} <input type="text" name="first_name" required> <input type="text" name="last_name" required> <input type="text" name="username" required> <input type="email" name="email" required> <input type="password" name="password" required> <input type="password" name="confirm_password" required> <button type="submit">Register</button> </form>

Login Form (login.html)

<form method="POST"> {% csrf_token %} <input type="text" name="username" required> <input type="password" name="password" required> <button type="submit">Login</button> </form>

Forgot Password Form (forgot_password.html)

<form method="POST"> {% csrf_token %} <input type="email" name="email" required> <button type="submit">Send Reset Link</button> </form>

Reset Password Form (reset_password.html)

<form method="POST"> {% csrf_token %} <input type="password" name="password" required> <input type="password" name="confirm_password" required> <button type="submit">Reset Password</button> </form>

Error Handling

The system includes comprehensive error handling:

  • Form validation errors are displayed using Django messages framework
  • Invalid reset tokens redirect to appropriate error pages
  • Expired reset links are automatically cleaned up
  • User-friendly error messages for all failure scenarios

Usage Examples

Protecting Views

from django.contrib.auth.decorators import login_required @login_required def protected_view(request): return render(request, 'protected.html')

Displaying Messages in Templates

{% if messages %} {% for message in messages %} <div class="alert alert-{{ message.tags }}">{{ message }}</div> {% endfor %} {% endif %}

Contributing

  1. Fork the repository
  2. Create your feature branch (git checkout -b feature/AmazingFeature)
  3. Commit your changes (git commit -m 'Add some AmazingFeature')
  4. Push to the branch (git push origin feature/AmazingFeature)
  5. Open a Pull Request

Support

If you encounter any issues or have questions, please open an issue on GitHub.

About

A complete Django authentication system with user registration, login, logout, and secure password reset functionality using session-based authentication and email verification.

Topics

Resources

Stars

Watchers

Forks

Releases

No releases published

Packages

No packages published