feat: add user authentication with separate login and register pages

- Custom User model with email as unique identifier (AUTH_USER_MODEL)

- POST /api/auth/register/ with email validation, password min 8 chars, duplicate rejection

- POST /api/auth/login/ returning JWT (access + refresh) tokens

- Passwords hashed via Django's make_password

- React LoginPage and RegisterPage with form validation

- AuthContext with useReducer for auth state management

- Axios API client with JWT token injection

- TypeScript conversion of frontend scaffold
This commit is contained in:
Marko (Hermes Implementer)
2026-05-26 00:54:27 +00:00
parent b91b7c364e
commit 6867a91b67
28 changed files with 3313 additions and 55 deletions
+27 -3
View File
@@ -1,5 +1,6 @@
import os
from pathlib import Path
from datetime import timedelta
BASE_DIR = Path(__file__).resolve().parent.parent
@@ -15,6 +16,9 @@ ALLOWED_HOSTS: list[str] = ["*"]
INSTALLED_APPS = [
"django.contrib.contenttypes",
"django.contrib.auth",
"django.contrib.sessions",
"rest_framework",
"accounts",
]
MIDDLEWARE = [
@@ -48,10 +52,10 @@ WSGI_APPLICATION = "project.wsgi.application"
# Parse DATABASE_URL
_database_url = os.environ.get(
"DATABASE_URL",
"postgres://jobtracker:jobtracker@localhost:5432/jobtracker",
"postgres://jobtracker:***@localhost:5432/jobtracker",
)
# postgres://user:password@host:port/dbname → django settings dict
# postgres://user:***@host:port/dbname → django settings dict
_db_parts = _database_url.replace("postgres://", "").split("@")
_credentials, _host_db = _db_parts[0], _db_parts[1]
_db_user, _db_pass = _credentials.split(":")
@@ -70,9 +74,29 @@ DATABASES = {
}
}
AUTH_USER_MODEL = "accounts.User"
REST_FRAMEWORK = {
"DEFAULT_AUTHENTICATION_CLASSES": (
"rest_framework_simplejwt.authentication.JWTAuthentication",
),
"DEFAULT_PERMISSION_CLASSES": (
"rest_framework.permissions.AllowAny",
),
"DEFAULT_RENDERER_CLASSES": (
"rest_framework.renderers.JSONRenderer",
),
}
SIMPLE_JWT = {
"ACCESS_TOKEN_LIFETIME": timedelta(hours=24),
"REFRESH_TOKEN_LIFETIME": timedelta(days=30),
"AUTH_HEADER_TYPES": ("Bearer",),
}
LANGUAGE_CODE = "en-us"
TIME_ZONE = "UTC"
USE_I18N = True
USE_TZ = True
DEFAULT_AUTO_FIELD = "django.db.models.BigAutoField"
DEFAULT_AUTO_FIELD = "django.db.models.BigAutoField"
+4 -2
View File
@@ -1,4 +1,6 @@
from django.contrib import admin
from django.urls import path
from django.urls import include, path
urlpatterns: list = []
urlpatterns: list = [
path("api/auth/", include("accounts.urls", namespace="accounts")),
]