# 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

```python
# 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

```python
# 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

```python
# 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

```python
# 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

```python
# 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

- [django-allauth Documentation](https://django-allauth.readthedocs.io/)
- [djangorestframework-simplejwt](https://django-rest-framework-simplejwt.readthedocs.io/)
- [OAuth 2.0 Specification](https://oauth.net/2/)
- [JWT Best Practices](https://auth0.com/blog/jwt-security-best-practices/)
