mirror of
https://github.com/pacnpal/thrillwiki_django_no_react.git
synced 2025-12-24 13:31:09 -05:00
- 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.
6.5 KiB
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
- Flexibility: Multiple auth methods for different use cases
- Security: JWT with short-lived access tokens
- User Experience: Social login reduces friction
- Standards-Based: OAuth2 and JWT are industry standards
- Django Integration: Seamless with Django's user model
Trade-offs
- Complexity: Multiple auth systems to maintain
- Token Management: Must handle token refresh client-side
- 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
- Password Hashing: Django's PBKDF2 with SHA256
- Token Blacklisting: Invalidated refresh tokens stored
- Rate Limiting: Login attempts limited
- HTTPS Required: Tokens only sent over secure connections