Skip to content

Authentication API

Tonnnya edited this page Oct 19, 2025 · 2 revisions

Authentication API

Overview

This module provides user registration and email verification functionality for both startup and investor roles.

Endpoints

1. User Registration

Endpoint: POST /api/auth/register/

Description: Register a new user account with role-specific profile creation.

Request Body

Common fields (required for all roles):

  • email (string, required): User's email address
  • password (string, required): Password (must meet Django password validation rules)
  • first_name (string, required): User's first name (max 150 characters)
  • last_name (string, required): User's last name (max 150 characters)
  • role (string, required): User role - either "startup" or "investor"

Startup-specific fields:

  • company_name (string, required): Company name (max 255 characters)
  • description (string, optional): Company description
  • website (string, optional): Company website URL
  • phone (string, optional): Contact phone number (max 20 characters)

Investor-specific fields:

  • investment_range_min (decimal, required): Minimum investment amount (max 12 digits, 2 decimal places)
  • investment_range_max (decimal, optional): Maximum investment amount (max 12 digits, 2 decimal places)

Examples

Startup Registration:

POST /api/auth/register/
Content-Type: application/json

{
  "email": "alice@example.com",
  "password": "SecurePass123!",
  "first_name": "Alice",
  "last_name": "Smith",
  "role": "startup",
  "company_name": "Handmade Co",
  "description": "Woodwork & ceramics",
  "website": "https://example.com",
  "phone": "+380123456789"
}

Investor Registration:

POST /api/auth/register/
Content-Type: application/json

{
  "email": "bob@investor.com",
  "password": "SecurePass123!",
  "first_name": "Bob",
  "last_name": "Johnson",
  "role": "investor",
  "investment_range_min": 10000.00,
  "investment_range_max": 100000.00
}

Success Response

Status Code: 201 Created

{
  "id": 123,
  "email": "alice@example.com",
  "detail": "Verification email sent."
}

Error Responses

Validation Error - 400 Bad Request

{
  "email": ["Enter a valid email address."],
  "password": ["This password is too short. It must contain at least 8 characters."]
}

Missing Required Field - 400 Bad Request

{
  "first_name": ["This field is required."]
}
{
  "company_name": ["This field is required for startups"]
}
{
  "investment_range_min": ["This field is required for investors"]
}

Duplicate Email - 201 Created (Anti-enumeration)

{
  "detail": "Verification email sent."
}

Password Requirements

Passwords must meet Django's default validation rules:

  • At least 8 characters
  • Not entirely numeric
  • Not too similar to user information
  • Not a commonly used password

2. Email Verification

Endpoint: GET /api/auth/verify/<str:uid>/<str:token>/

Description: Verify user's email address using the token sent via email.

Path Parameters

  • uid (string): Base64-encoded user ID
  • token (string): Verification token

Example

GET /api/auth/verify/MQ/abc123-def456/

Success Response

Status Code: 200 OK

{
  "detail": "Email verified successfully."
}

Already Verified - 200 OK

{
  "detail": "Email already verified. You can log in."
}

After successful verification:

  • User's is_active status is set to true
  • User can now log in

Error Responses

Invalid or Expired Token - 400 Bad Request

{
  "detail": "Invalid or expired token."
}

Invalid Verification Link - 400 Bad Request

{
  "detail": "Invalid verification link."
}

Security Features

Anti-Enumeration Policy

This API implements a strict anti-enumeration approach to prevent attackers from discovering registered email addresses:

  • All registration attempts return HTTP 201 with identical messages
  • Duplicate email registrations are silently ignored:
    • No new user is created
    • No verification email is sent
    • Response is identical to successful registration
  • From the client's perspective, responses are indistinguishable

Rationale: This prevents attackers from determining which emails are registered by observing different response codes or messages.

Trade-off: Users won't know if they're already registered, but overall security is improved.

Email Verification

  • Users are created with is_active=False by default
  • Verification email is sent automatically upon registration
  • Users must verify their email before they can authenticate
  • Verification tokens are single-use and expire after a period

URL Configuration

from django.urls import path
from .views import RegisterView, VerifyEmailView

urlpatterns = [
    path('register/', RegisterView.as_view(), name='register'),
    path('verify/<str:uid>/<str:token>/', VerifyEmailView.as_view(), name='verify-email')
]

Testing

Run All Tests

docker-compose exec backend python manage.py test apps.authentication

Run Specific Test Cases

# Registration tests only
docker-compose exec backend python manage.py test apps.authentication.tests.RegistrationTestCase

# Email verification tests only
docker-compose exec backend python manage.py test apps.authentication.tests.EmailVerificationTestCase

Test Coverage

The test suite covers:

  • ✅ Successful startup registration
  • ✅ Successful investor registration
  • ✅ Missing first_name validation
  • ✅ Missing last_name validation
  • ✅ Password validation (weak passwords rejected)
  • ✅ Email format validation
  • ✅ Missing required fields (company_name, investment_range_min)
  • ✅ Role-specific validation
  • ✅ Duplicate email anti-enumeration
  • ✅ Successful email verification
  • ✅ Invalid tokens
  • ✅ Invalid UIDs
  • ✅ Non-existent users

Email Configuration

Development (Console Backend)

By default, emails are printed to the console for development:

# settings.py
EMAIL_BACKEND = 'django.core.mail.backends.console.EmailBackend'

View emails in Docker logs:

docker-compose logs -f backend

API Testing with Postman

Register a Startup

POST /api/auth/register/
Content-Type: application/json

{
  "email": "startup@test.com",
  "password": "SecurePass123!",
  "first_name": "John",
  "last_name": "Doe",
  "role": "startup",
  "company_name": "Test Startup",
  "description": "Innovative solutions",
  "website": "https://test.com",
  "phone": "+380123456789"
}

Register an Investor

POST /api/auth/register/
Content-Type: application/json

{
  "email": "investor@test.com",
  "password": "SecurePass123!",
  "first_name": "Jane",
  "last_name": "Smith",
  "role": "investor",
  "investment_range_min": 50000,
  "investment_range_max": 500000
}

Verify Email

# Replace <uid> and <token> with values from verification email
curl http://localhost:8000/api/auth/verify/<uid>/<token>/

Common Issues

Issue: Verification email not received

Solution: Check Docker logs for email output:

docker-compose logs backend | grep -A 10 "Verify your email"

Issue: "This field is required" for optional fields

Solution: Ensure all required fields are provided:

  • Common: email, password, first_name, last_name, role
  • Startup: company_name is required
  • Investor: investment_range_min is required

Issue: Password validation errors

Solution: Ensure password meets requirements:

  • Minimum 8 characters
  • Mix of letters and numbers
  • Not a common password

Issue: Tests failing

Solution: Rebuild Docker container:

docker-compose down
docker-compose up --build -d
docker-compose exec backend python manage.py migrate
docker-compose exec backend python manage.py test apps.authentication

Notes

  • Users are created with is_active=False and must verify their email before logging in
  • Verification links are sent to the email provided during registration
  • In DEBUG mode, verification links point to localhost:8000
  • In production, verification links use FRONTEND_URL from settings
  • All profile fields beyond the required ones are auto-populated with default values