Files
thrillwiki_django_no_react/docs/architecture/adr-005-authentication-approach.md
pacnpal edcd8f2076 Add secret management guide, client-side performance monitoring, and search accessibility enhancements
- Introduced a comprehensive Secret Management Guide detailing best practices, secret classification, development setup, production management, rotation procedures, and emergency protocols.
- Implemented a client-side performance monitoring script to track various metrics including page load performance, paint metrics, layout shifts, and memory usage.
- Enhanced search accessibility with keyboard navigation support for search results, ensuring compliance with WCAG standards and improving user experience.
2025-12-23 16:41:42 -05:00

6.5 KiB

ADR-005: Authentication Approach

Status

Accepted

Context

ThrillWiki needs to authenticate users for:

  • Web browsing (session-based)
  • API access (token-based)
  • Social login (Google, Discord)

We needed an authentication approach that would:

  • Support multiple authentication methods
  • Provide secure token handling for API
  • Enable social authentication
  • Work seamlessly with Django + HTMX architecture

Decision

We implemented a Hybrid Authentication System using django-allauth for social auth and djangorestframework-simplejwt for API tokens.

Authentication Methods

Context Method Library
Web browsing Session-based Django sessions
API access JWT tokens djangorestframework-simplejwt
Social login OAuth2 django-allauth
Password reset Email tokens Django built-in

Architecture

┌─────────────────────────────────────────────────────────┐
│                    User Request                         │
└─────────────────────────────────────────────────────────┘
                           │
           ┌───────────────┼───────────────┐
           │               │               │
           ▼               ▼               ▼
┌─────────────────┐ ┌─────────────────┐ ┌─────────────────┐
│   Web Request   │ │   API Request   │ │  Social Auth    │
│                 │ │                 │ │                 │
│  Session Cookie │ │  Bearer Token   │ │  OAuth Flow     │
└─────────────────┘ └─────────────────┘ └─────────────────┘
           │               │               │
           └───────────────┼───────────────┘
                           ▼
               ┌─────────────────────┐
               │   Django User       │
               │   (Authenticated)   │
               └─────────────────────┘

JWT Token Configuration

# backend/config/settings/rest_framework.py
SIMPLE_JWT = {
    'ACCESS_TOKEN_LIFETIME': timedelta(minutes=15),
    'REFRESH_TOKEN_LIFETIME': timedelta(days=7),
    'ROTATE_REFRESH_TOKENS': True,
    'BLACKLIST_AFTER_ROTATION': True,
    'ALGORITHM': 'HS256',
    'SIGNING_KEY': SECRET_KEY,
    'AUTH_HEADER_TYPES': ('Bearer',),
}

Social Authentication

# backend/config/settings/third_party.py
SOCIALACCOUNT_PROVIDERS = {
    'google': {
        'SCOPE': ['profile', 'email'],
        'AUTH_PARAMS': {'access_type': 'online'},
    },
    'discord': {
        'SCOPE': ['identify', 'email'],
    },
}

Consequences

Benefits

  1. Flexibility: Multiple auth methods for different use cases
  2. Security: JWT with short-lived access tokens
  3. User Experience: Social login reduces friction
  4. Standards-Based: OAuth2 and JWT are industry standards
  5. Django Integration: Seamless with Django's user model

Trade-offs

  1. Complexity: Multiple auth systems to maintain
  2. Token Management: Must handle token refresh client-side
  3. Social Provider Dependency: Reliance on third-party OAuth providers

Authentication Flow

Web Session Authentication

1. User visits /login/
2. User submits credentials
3. Django validates credentials
4. Session created, cookie set
5. Subsequent requests include session cookie

API JWT Authentication

1. Client POST /api/v1/auth/login/
   {username, password}
2. Server validates, returns tokens
   {access: "...", refresh: "..."}
3. Client includes in requests:
   Authorization: Bearer <access_token>
4. On 401, client refreshes:
   POST /api/v1/auth/token/refresh/
   {refresh: "..."}

Social Authentication

1. User clicks "Login with Google"
2. Redirect to Google OAuth
3. User authorizes application
4. Google redirects with auth code
5. Server exchanges code for tokens
6. Server creates/updates user
7. Session created

Alternatives Considered

Session-Only Authentication

Rejected because:

  • Not suitable for mobile apps
  • Not RESTful for API access
  • CSRF complexity for API clients

JWT-Only Authentication

Rejected because:

  • More complex for web browsing
  • Token storage in browser has security concerns
  • Session logout not immediate

OAuth2 Server (Self-Hosted)

Rejected because:

  • Significant complexity for current needs
  • django-oauth-toolkit overkill
  • django-allauth sufficient for social auth

Implementation Details

Permission Classes

# API views use JWT or session authentication
REST_FRAMEWORK = {
    'DEFAULT_AUTHENTICATION_CLASSES': [
        'rest_framework_simplejwt.authentication.JWTAuthentication',
        'rest_framework.authentication.SessionAuthentication',
    ],
    'DEFAULT_PERMISSION_CLASSES': [
        'rest_framework.permissions.IsAuthenticatedOrReadOnly',
    ],
}

Custom User Model

# backend/apps/accounts/models.py
class User(AbstractUser):
    email = models.EmailField(unique=True)
    display_name = models.CharField(max_length=50, blank=True)
    avatar_url = models.URLField(blank=True)
    email_verified = models.BooleanField(default=False)

    USERNAME_FIELD = 'email'
    REQUIRED_FIELDS = ['username']

Email Verification

# Required before full access
ACCOUNT_EMAIL_VERIFICATION = 'mandatory'
ACCOUNT_EMAIL_REQUIRED = True
ACCOUNT_AUTHENTICATION_METHOD = 'email'

Security Measures

  1. Password Hashing: Django's PBKDF2 with SHA256
  2. Token Blacklisting: Invalidated refresh tokens stored
  3. Rate Limiting: Login attempts limited
  4. HTTPS Required: Tokens only sent over secure connections

References