You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
A full-stack Django project with a REST API for user profile management and a vanilla JS web frontend. Includes JWT-based authentication, role-based routing, password change, and forgot-password via email.
3. Create .env inside machine_test/ (next to settings.py)
SECRET_KEY=your-secret-key-hereDEBUG=True
4. Run migrations
python manage.py migrate
5. Seed the database (states, cities, hobbies)
python manage.py seed_db
6. Collect static files
python manage.py collectstatic --noinput
7. Start the server
python manage.py runserver 0.0.0.0:8000
Web Pages
Page
URL
Access
Root
/
Redirects to /login/
Login
/login/
Public — redirects away if already logged in
Register
/register/
Public
My Profile
/profile/
Authenticated users only — redirects to /login/ if unauthenticated
Forgot Password
/forgot-password/
Public
Reset Password
/reset-password/?token=<token>
Public — token arrives via email link
User List
/users/
Admin only — redirects to /login/ or /profile/ if not admin
Features
Web Frontend
Login — authenticate with username + password; admin users are routed to /users/, regular users to /profile/; shows success message when arriving from a password reset
Register — create an account with a user-chosen username (≥4 letters + ≥4 digits), password, and full profile details; redirects to /profile/ on success
My Profile — view your own profile including name, photo, gender, DOB, location, and hobbies; includes a working Change Password modal
Change Password — modal on the profile page; requires current password; calls POST /api/change-password/; shows a success toast on completion
Forgot Password — email entry page at /forgot-password/; calls POST /api/forgot-password/; shows confirmation after submission
Reset Password — form at /reset-password/?token=<token> (link sent via email); validates the token and sets a new password; redirects to login with a success message
User List (admin only) — filterable by name, state, and gender; sortable by any column; configurable page size; sparse fieldset to trim API response
Password visibility toggle — eye icon on all password inputs (login, register, Change Password modal, reset password)
Auto token refresh — expired access tokens are refreshed silently using the refresh token; user is only redirected to login if the refresh also fails
Auth guards — every protected page checks token presence and admin status on load; unauthorized access redirects instantly
API
JWT Authentication — register and login return access + refresh tokens; send Authorization: Bearer <access> for protected endpoints
Register — creates a UserProfile and linked Django User atomically; returns tokens immediately so the client is logged in right after signup
Login — exchange username + password for a token pair; response includes is_admin flag for client-side routing
Token refresh — get a new access token using a valid refresh token
Profile — get the full profile of the authenticated user
Change password — authenticated endpoint; verifies current password before updating
Forgot password — sends a single-use 15-minute reset token to the user's registered email
Reset password — consumes the token and sets the new password
User list — paginated (10/page default, max 100), filterable, sortable, with sparse fieldsets
Hobbies list — fetch all available hobbies with their IDs for use in the registration form
API Endpoints
Method
URL
Auth
Description
GET
/api/states/
No
List all states
GET
/api/cities/?state_id=<id>
No
List cities for a state
GET
/api/hobbies/
No
List all hobbies
POST
/api/register/
No
Register — returns JWT tokens
POST
/api/login/
No
Login — returns JWT tokens + is_admin
POST
/api/token/refresh/
No
Refresh access token
GET
/api/profile/
Bearer token
Get own profile
POST
/api/change-password/
Bearer token
Change password (requires current password)
POST
/api/forgot-password/
No
Send password reset email
POST
/api/forgot-password/confirm/
No
Set new password using reset token
GET
/api/users/
Admin only
List users — filterable, sortable, paginated
See API_DOCS.md for full request/response details.
Interactive docs (server must be running):
Tool
URL
Swagger UI
http://localhost:8000/api/docs/
ReDoc
http://localhost:8000/api/redoc/
Authentication Flow
Register — POST /api/register/ with a chosen username (alphanumeric, ≥4 letters + ≥4 digits), password, and profile data → save the returned access, refresh, and username tokens
Login — POST /api/login/ with username + password → save access, refresh, username, is_admin; route to /users/ if admin, /profile/ otherwise
Make authenticated requests — add Authorization: Bearer <access_token> to the Authorization header
Silent refresh — when a request returns 401, automatically retry POST /api/token/refresh/ with the stored refresh token and replay the original request with the new access token
Logout — clear all stored tokens from localStorage; redirect to /login/
Change password — POST /api/change-password/ with old_password, new_password, confirm_password; the active session remains valid after a successful change
Forgot password — POST /api/forgot-password/ with email; a reset link is emailed to /reset-password/?token=<token>; the token expires in 15 minutes
Reset password — POST /api/forgot-password/confirm/ with token, new_password, confirm_password; on success the token is consumed and the user is redirected to /login/
Known Issues
Issues that existed at project start and are still open. None of these affect core functionality in a local development context but must be resolved before any public or production deployment.
Medium
#
Issue
Where
Impact
1
CORS middleware in wrong position
settings.py — MIDDLEWARE
CorsMiddleware must be first in the list. It is currently last, so CORS headers are never added. Cross-origin requests from mobile apps or separate frontends will be blocked.
2
No CORS origins configured
settings.py
Neither CORS_ALLOWED_ORIGINS nor CORS_ALLOW_ALL_ORIGINS is set. Even after fixing position, no CORS headers will be sent until one of these is configured.
3
No server-side token blacklist
—
There is no token blacklist. Once issued, an access token is valid until it naturally expires. A stolen access token cannot be revoked. Client-side logout (clearing localStorage) is implemented but does not invalidate tokens on the server.