Skip to content

About

A security-focused Django REST Framework authentication platform featuring JWT access/refresh tokens, refresh token rotation and reuse detection, Iranian phone OTP authentication, Redis-based rate limiting and hybrid state management, session tracking, RBAC, audit logging, device/IP tracking, and comprehensive security testing.

Topics

Resources

Stars

10 stars

Watchers

0 watching

Forks

Repository files navigation

🔐 Secure OTP + JWT Authentication System

Passwordless · Session-Bound · Token Rotation & Blacklist · Rate-Limited

Django DRF Python Tests Redis Celery Docker License

🇬🇧 English | 🇮🇷 فارسی



🇬🇧 English Documentation

Language: 🇬🇧 English · 🇮🇷 فارسی

📖 Overview

A production-grade, passwordless authentication platform built on Django REST Framework.

Users authenticate via a 6-digit OTP delivered over SMS (Kavenegar) or printed to the console in development. On success the system issues a short-lived JWT Access Token (15 min) and a rotating, blacklisting Refresh Token (7 d) — each cryptographically bound to a tracked Session (device fingerprint, IP address, User-Agent). Every request is validated against the session state, and all sensitive operations are protected by multi-layer rate limiting, asynchronous audit logging, token-reuse detection, and IDOR prevention.

✨ Features

# Feature
1 Passwordless OTP login / registration
2 JWT Access (15 min) + Refresh (7 days)
3 Refresh Token Rotation + Blacklist
4 Token Reuse Detection → revokes all sessions
5 Session management (list / revoke / revoke-all)
6 Device fingerprint + IP + User-Agent tracking
7 Multi-layer Rate Limiting + automatic IP blocking
8 Async Audit Log + Security Events
9 Cookie-based auth (HttpOnly refresh token)
10 IDOR Prevention on sessions & profile
11 drf-yasg Swagger / ReDoc documentation
12 140 automated tests — 100% passing

🏗️ Architecture

┌─────────────┐  HTTP   ┌────────────┐        ┌─────────────────┐
│ Client /    │ ──────► │ Nginx :80  │ ─────► │ Gunicorn :8000  │
│ Postman /   │         └────────────┘        │ (Django + DRF)  │
│ Swagger     │                               └───────┬─────────┘
└─────────────┘                                       │
                    ┌─────────────────────────────────┼─────────────────────────┐
                    │                                 │                         │
              ┌─────▼──────┐   Cache/OTP       ┌──────▼───────┐        ┌───────▼───────┐
              │   Redis    │ ◄───────────────► │   Celery     │        │    SQLite     │
              │ Broker +   │ ── Broker ──────► │   Worker     │        │  (WAL mode)   │
              │   Cache    │                   └──────────────┘        └───────────────┘
              └────────────┘

Docker services: backend · celery_worker · redis · nginx · locust master/worker · smtp4dev

🛡️ Security Measures

1. OTP Security

The OTP is never stored in plain text. An HMAC-SHA256 hash — keyed by SECRET_KEY + phone_number + purpose — is written to Redis with a 5-minute TTL. A maximum of 3 verification attempts is allowed; exceeding this invalidates the OTP.

2. JWT Lifecycle

On every refresh the previous token is blacklisted and a fresh pair is issued (Rotation). Any attempt to reuse a blacklisted token raises a SecurityEvent and revokes all of the user's sessions and outstanding tokens.

3. Session Binding

Each token carries a session_id. The custom CustomJWTAuthentication backend verifies on every request that the session exists, is not revoked, and is not expired.

4. Rate Limiting Matrix

Scope Limit
OTP request / IP 3 / 60s
OTP request / phone 5 / 600s
Resend cooldown 1 / 120s
OTP verify / phone 5 / 300s
Failed verify → IP block 5 → 15 min

5. Cookie Security

refresh_token is set as HttpOnly + SameSite=Lax (XSS/CSRF mitigation). access_token is readable for SPA consumption. Both are cleared on logout.

6. Additional Controls

  • IDOR prevention on sessions & profile endpoints
  • Asynchronous audit log & security events via Celery
  • SQLite WAL mode for concurrent writes
  • CORS allow-credentials configured
  • Strict input validation via DRF serializers

🔌 API Endpoints

Method Endpoint Auth Description
POST /api/v1/accounts/otp/request/ ✗ Request OTP
POST /api/v1/accounts/otp/verify/ ✗ Verify OTP → tokens + cookies
POST /api/v1/accounts/refresh/ ✗ Refresh token pair
POST /api/v1/accounts/logout/ ✓ Logout + revoke
GET/PUT/PATCH /api/v1/accounts/profile/ ✓ Profile CRUD
GET /api/v1/accounts/sessions/ ✓ List active sessions
DELETE /api/v1/accounts/sessions/{id}/ ✓ Revoke a session
POST /api/v1/accounts/sessions/revoke-all/ ✓ Revoke all sessions

📚 Interactive docs: http://localhost/swagger/ · http://localhost/redoc/

🔄 Authentication Flow

[1] POST /otp/request/  ──► rate-limit ──► generate OTP ──► hash → Redis ──► SMS/Console
[2] POST /otp/verify/   ──► verify hash ──► create user+session ──► issue JWT pair ──► set cookies
[3] GET  /profile/      ──► CustomJWTAuthentication ──► validate session ──► 200 / 401
[4] POST /refresh/      ──► blacklist old ──► issue new pair (rotation)
[5] POST /logout/       ──► blacklist + revoke session ──► clear cookies

📸 Screenshots

A few previews below — see the full gallery in screenshots/.

Postman — OTP Request

Postman OTP Request

Postman — OTP Verify

Postman OTP Verify

Postman — Get Profile (Cookie auth)

Postman Profile

Swagger — Token Refresh

Swagger Token Refresh

Swagger — Sessions List

Swagger Sessions

Locust — 100 User Request Tests

Charts

Locust — 100 User Request Tests

Table

Django Admin — Blacklisted Tokens

Admin Blacklist

➡️ Full gallery (15 screenshots): screenshots/README.md

🧪 Test Results

✅ 140 passed, 0 failed — in 9.29s

=================================================== test session starts ===================================================
platform linux -- Python 3.12.11, pytest-8.2.2, pluggy-1.6.0
django: version: 5.2.17, settings: core.settings.development (from ini)
plugins: django-4.8.0, Faker-33.3.1
collected 140 items

accounts/tests/test_api/test_auth_endpoints.py::TestOTPRequest::test_request_otp_success PASSED
accounts/tests/test_api/test_auth_endpoints.py::TestOTPVerify::test_verify_otp_success PASSED
accounts/tests/test_api/test_auth_endpoints.py::TestTokenRefresh::test_refresh_reuse_detection PASSED
accounts/tests/test_security/test_token_reuse.py::TestIDORPrevention::test_user_profile_isolation PASSED
... (136 more)
=================================================== 140 passed in 9.29s ==================================================
Module Tests Status
API — Authentication 31 ✅
API — Profile & Sessions 18 ✅
Security — Rate Limiting 15 ✅
Security — Token Reuse 16 ✅
Services 29 ✅
Models 17 ✅
Managers 14 ✅
Total 140 ✅ 100%

📄 Full breakdown: TEST_RESULTS.md

🚀 Quick Start

# 1. Configure
cp .env.example .env          # set SECRET_KEY, REDIS_HOST=redis, ...

# 2. Build & run
docker compose up -d --build

# 3. Open docs
#    Swagger → http://localhost/swagger/
#    ReDoc   → http://localhost/redoc/

# 4. Run tests
docker compose exec backend pytest accounts/tests/ -v

Environment Variables

Variable Description
SECRET_KEY Django secret key
DEBUG Debug mode
REDIS_HOST / REDIS_PORT Redis address
CELERY_BROKER_URL Celery broker URL
KAVENEGAR_API_KEY SMS provider key
CORS_ALLOWED_ORIGINS Allowed origins

📁 Project Structure

django-secure-auth/
├── core/                    # Settings, URLs, Celery, WSGI/ASGI
├── accounts/
│   ├── models.py            # User, Profile, Session, OTPRecord, AuditLog, SecurityEvent
│   ├── managers.py          # UserManager (phone normalization)
│   ├── auth.py              # CustomJWTAuthentication (Header + Cookie + Session)
│   ├── services/            # otp.py, auth.py, security.py, sms.py
│   ├── tasks.py             # Celery tasks
│   ├── api/v1/              # views / serializers / urls
│   └── tests/               # 140 tests
├── docker/                  # Dockerfile, entrypoint, nginx
├── locust/                  # Load testing
├── screenshots/             # Postman / Swagger / Admin evidence
├── docker-compose.yml
├── README.md
└── TEST_RESULTS.md

🛠️ Development Tools

Tool Purpose
pytest + pytest-django Automated testing
ruff Linting
black Formatting
bandit Security scanning
locust Load testing

Author

Moein Rezaie — 📧 moeinrezaie516@gmail.com



🇮🇷 مستندات فارسی

زبان: 🇬🇧 English · 🇮🇷 فارسی

📖 نمای کلی

یک پلتفرم احراز هویت بدون رمز عبور با کیفیت تولید، ساخته‌شده روی Django REST Framework.

کاربران با یک کد OTP شش‌رقمی که از طریق پیامک (کاوه‌نگار) ارسال یا در محیط توسعه در کنسول چاپ می‌شود، احراز هویت می‌شوند. پس از موفقیت، سیستم یک توکن دسترسی کوتاه‌مدت (۱۵ دقیقه) و یک توکن نوسازی چرخشی با لیست‌سیاه (۷ روز) صادر می‌کند — که هر دو به‌صورت رمزنگارانه به یک نشست ردیابی‌شده (اثر انگشت دستگاه، آدرس IP، User-Agent) متصل‌اند. هر درخواست در برابر وضعیت نشست اعتبارسنجی می‌شود و همه عملیات‌های حساس با محدودسازی نرخ چندلایه، لاگ حسابرسی ناهمگام، تشخیص استفاده مجدد توکن و جلوگیری از IDOR محافظت می‌شوند.

✨ ویژگی‌ها

# ویژگی
۱ ورود / ثبت‌نام بدون رمز عبور با OTP
۲ توکن دسترسی (۱۵ دقیقه) + توکن نوسازی (۷ روز)
۳ چرخش توکن نوسازی + لیست سیاه
۴ تشخیص استفاده مجدد توکن → ابطال همه نشست‌ها
۵ مدیریت نشست‌ها (لیست / ابطال / ابطال همه)
۶ ردیابی اثر انگشت دستگاه + IP + User-Agent
۷ محدودسازی نرخ چندلایه + مسدودسازی خودکار IP
۸ لاگ حسابرسی + رویدادهای امنیتی ناهمگام
۹ احراز هویت کوکی‌محور (توکن نوسازی HttpOnly)
۱۰ جلوگیری از IDOR در نشست‌ها و پروفایل
۱۱ مستندات Swagger / ReDoc با drf-yasg
۱۲ ۱۴۰ تست خودکار — ۱۰۰٪ موفق

🏗️ معماری

┌─────────────┐  HTTP   ┌────────────┐        ┌─────────────────┐
│ کلاینت /    │ ──────► │ Nginx :80  │ ─────► │ Gunicorn :8000  │
│ Postman /   │         └────────────┘        │ (Django + DRF)  │
│ Swagger     │                               └───────┬─────────┘
└─────────────┘                                       │
                    ┌─────────────────────────────────┼─────────────────────────┐
                    │                                 │                         │
              ┌─────▼──────┐   Cache/OTP       ┌──────▼───────┐        ┌───────▼───────┐
              │   Redis    │ ◄───────────────► │   Celery     │        │    SQLite     │
              │ Broker +   │ ── Broker ──────► │   Worker     │        │  (حالت WAL)   │
              │   Cache    │                   └──────────────┘        └───────────────┘
              └────────────┘

سرویس‌های Docker: backend · celery_worker · redis · nginx · locust master/worker · smtp4dev

🛡️ اقدامات امنیتی

۱. امنیت OTP

کد OTP هرگز به‌صورت متن ساده ذخیره نمی‌شود. یک هش HMAC-SHA256 — با کلید SECRET_KEY + شماره تلفن + هدف — با انقضای ۵ دقیقه در Redis نوشته می‌شود. حداکثر ۳ تلاش تأیید مجاز است؛ با عبور از این حد، OTP باطل می‌شود.

۲. چرخه حیات JWT

در هر نوسازی، توکن قبلی لیست‌سیاه و یک جفت جدید صادر می‌شود (چرخش). هر تلاش برای استفاده مجدد از توکن لیست‌سیاه، یک SecurityEvent ثبت کرده و همه نشست‌ها و توکن‌های فعال کاربر را باطل می‌کند.

۳. اتصال نشست

هر توکن یک session_id حمل می‌کند. بک‌اند سفارشی CustomJWTAuthentication در هر درخواست تأیید می‌کند که نشست وجود دارد، باطل نشده و منقضی نشده است.

۴. جدول محدودسازی نرخ

محدوده محدودیت
درخواست OTP / IP ۳ در ۶۰ ثانیه
درخواست OTP / شماره ۵ در ۱۰ دقیقه
بازارسال ۱ در ۲ دقیقه
تأیید OTP / شماره ۵ در ۵ دقیقه
تأیید ناموفق → مسدودی IP ۵ → ۱۵ دقیقه

۵. امنیت کوکی

کوکی refresh_token با HttpOnly + SameSite=Lax تنظیم می‌شود (کاهش XSS/CSRF). کوکی access_token برای مصرف SPA قابل خواندن است. هر دو در خروج پاک می‌شوند.

۶. کنترل‌های تکمیلی

  • جلوگیری از IDOR در نقاط پایانی نشست‌ها و پروفایل
  • لاگ حسابرسی و رویدادهای امنیتی ناهمگام با Celery
  • حالت WAL در SQLite برای نوشتارهای هم‌زمان
  • پیکربندی CORS با allow-credentials
  • اعتبارسنجی سخت‌گیرانه ورودی با سریالایزرهای DRF

🔌 نقاط پایانی API

متد مسیر احراز هویت توضیح
POST /api/v1/accounts/otp/request/ ✗ درخواست OTP
POST /api/v1/accounts/otp/verify/ ✗ تأیید OTP → توکن + کوکی
POST /api/v1/accounts/refresh/ ✗ نوسازی جفت توکن
POST /api/v1/accounts/logout/ ✓ خروج + ابطال
GET/PUT/PATCH /api/v1/accounts/profile/ ✓ عملیات پروفایل
GET /api/v1/accounts/sessions/ ✓ لیست نشست‌های فعال
DELETE /api/v1/accounts/sessions/{id}/ ✓ ابطال یک نشست
POST /api/v1/accounts/sessions/revoke-all/ ✓ ابطال همه نشست‌ها

📚 مستندات تعاملی: http://localhost/swagger/ · http://localhost/redoc/

🔄 جریان احراز هویت

[۱] POST /otp/request/  ──► محدودیت نرخ ──► تولید OTP ──► هش → Redis ──► پیامک/کنسول
[۲] POST /otp/verify/   ──► تأیید هش ──► ساخت کاربر+نشست ──► صدور جفت JWT ──► تنظیم کوکی‌ها
[۳] GET  /profile/      ──► CustomJWTAuthentication ──► اعتبارسنجی نشست ──► 200 / 401
[۴] POST /refresh/      ──► لیست‌سیاه قبلی ──► صدور جفت جدید (چرخش)
[۵] POST /logout/       ──► لیست‌سیاه + ابطال نشست ──► پاک‌سازی کوکی‌ها

📸 تصاویر

چند پیش‌نمایش در ادامه — گالری کامل در screenshots/.

Postman — درخواست OTP

Postman OTP Request

Postman — تأیید OTP

Postman OTP Verify

Postman — دریافت پروفایل (احراز هویت کوکی)

Postman Profile

Swagger — نوسازی توکن

Swagger Token Refresh

Swagger — لیست نشست‌ها

Swagger Sessions

Django Admin — توکن‌های لیست سیاه

Admin Blacklist

➡️ گالری کامل (۱۵ تصویر): screenshots/README.md

🧪 نتایج تست

✅ ۱۴۰ موفق، ۰ ناموفق — در ۹.۲۹ ثانیه

=================================================== test session starts ===================================================
platform linux -- Python 3.12.11, pytest-8.2.2, pluggy-1.6.0
django: version: 5.2.17, settings: core.settings.development (from ini)
plugins: django-4.8.0, Faker-33.3.1
collected 140 items

accounts/tests/test_api/test_auth_endpoints.py::TestOTPRequest::test_request_otp_success PASSED
accounts/tests/test_api/test_auth_endpoints.py::TestOTPVerify::test_verify_otp_success PASSED
accounts/tests/test_api/test_auth_endpoints.py::TestTokenRefresh::test_refresh_reuse_detection PASSED
accounts/tests/test_security/test_token_reuse.py::TestIDORPrevention::test_user_profile_isolation PASSED
... (136 more)
=================================================== 140 passed in 9.29s ==================================================
ماژول تعداد تست وضعیت
API — احراز هویت ۳۱ ✅
API — پروفایل و نشست‌ها ۱۸ ✅
امنیت — محدودیت نرخ ۱۵ ✅
امنیت — استفاده مجدد توکن ۱۶ ✅
سرویس‌ها ۲۹ ✅
مدل‌ها ۱۷ ✅
منیجرها ۱۴ ✅
مجموع ۱۴۰ ✅ ۱۰۰٪

📄 ریز کامل نتایج: TEST_RESULTS.md

🚀 شروع سریع

# ۱. پیکربندی
cp .env.example .env          # تنظیم SECRET_KEY, REDIS_HOST=redis, ...

# ۲. ساخت و اجرا
docker compose up -d --build

# ۳. باز کردن مستندات
#    Swagger → http://localhost/swagger/
#    ReDoc   → http://localhost/redoc/

# ۴. اجرای تست‌ها
docker compose exec backend pytest accounts/tests/ -v

متغیرهای محیطی

متغیر توضیح
SECRET_KEY کلید محرمانه جنگو
DEBUG حالت اشکال‌زدایی
REDIS_HOST / REDIS_PORT آدرس Redis
CELERY_BROKER_URL آدرس بروکر Celery
KAVENEGAR_API_KEY کلید ارائه‌دهنده پیامک
CORS_ALLOWED_ORIGINS دامنه‌های مجاز

📁 ساختار پروژه

django-secure-auth/
├── core/                    # تنظیمات، URLها، Celery، WSGI/ASGI
├── accounts/
│   ├── models.py            # User, Profile, Session, OTPRecord, AuditLog, SecurityEvent
│   ├── managers.py          # UserManager (نرمال‌سازی شماره تلفن)
│   ├── auth.py              # CustomJWTAuthentication (Header + Cookie + Session)
│   ├── services/            # otp.py, auth.py, security.py, sms.py
│   ├── tasks.py             # تسک‌های Celery
│   ├── api/v1/              # views / serializers / urls
│   └── tests/               # ۱۴۰ تست
├── docker/                  # Dockerfile, entrypoint, nginx
├── locust/                  # تست بار
├── screenshots/             # شواهد Postman / Swagger / Admin
├── docker-compose.yml
├── README.md
└── TEST_RESULTS.md

🛠️ ابزارهای توسعه

ابزار هدف
pytest + pytest-django تست خودکار
ruff لینتر
black قالب‌بندی کد
bandit اسکن امنیتی
locust تست بار

نویسنده

معین رضایی — 📧 moeinrezaie516@gmail.com

About

A security-focused Django REST Framework authentication platform featuring JWT access/refresh tokens, refresh token rotation and reuse detection, Iranian phone OTP authentication, Redis-based rate limiting and hybrid state management, session tracking, RBAC, audit logging, device/IP tracking, and comprehensive security testing.

Topics

Resources

Stars

10 stars

Watchers

0 watching

Forks

Releases

Packages

Contributors

Languages