# IndieAuth Server Removal Plan

## Executive Summary

This document provides a detailed, file-by-file plan for removing the custom IndieAuth authorization server from StarPunk and replacing it with external provider integration.

## Files to Delete (Complete Removal)

### Python Modules
```
/home/phil/Projects/starpunk/starpunk/tokens.py
  - Entire file (token generation, validation, storage)
  - ~300 lines of code

/home/phil/Projects/starpunk/tests/test_tokens.py
  - All token-related unit tests
  - ~200 lines of test code

/home/phil/Projects/starpunk/tests/test_routes_authorization.py
  - Authorization endpoint tests
  - ~150 lines of test code

/home/phil/Projects/starpunk/tests/test_routes_token.py
  - Token endpoint tests
  - ~150 lines of test code

/home/phil/Projects/starpunk/tests/test_auth_pkce.py
  - PKCE implementation tests
  - ~100 lines of test code
```

### Templates
```
/home/phil/Projects/starpunk/templates/auth/authorize.html
  - Authorization consent UI
  - ~100 lines of HTML/Jinja2
```

### Database Migrations
```
/home/phil/Projects/starpunk/migrations/002_secure_tokens_and_authorization_codes.sql
  - Table creation for authorization_codes and tokens
  - ~80 lines of SQL
```

## Files to Modify

### 1. `/home/phil/Projects/starpunk/starpunk/routes/auth.py`

**Remove**:
- Import of tokens module functions
- `authorization_endpoint()` function (~150 lines)
- `token_endpoint()` function (~100 lines)
- PKCE-related helper functions

**Keep**:
- Blueprint definition
- Admin login routes
- IndieLogin.com integration
- Session management

**New Structure**:
```python
"""
Authentication routes for StarPunk

Handles IndieLogin authentication flow for admin access.
External IndieAuth providers handle Micropub authentication.
"""

from flask import Blueprint, flash, redirect, render_template, session, url_for
from starpunk.auth import (
    handle_callback,
    initiate_login,
    require_auth,
    verify_session,
)

bp = Blueprint("auth", __name__, url_prefix="/auth")

@bp.route("/login", methods=["GET"])
def login_form():
    # Keep existing admin login

@bp.route("/callback")
def callback():
    # Keep existing callback

@bp.route("/logout")
def logout():
    # Keep existing logout

# DELETE: authorization_endpoint()
# DELETE: token_endpoint()
```

### 2. `/home/phil/Projects/starpunk/starpunk/auth.py`

**Remove**:
- PKCE code verifier generation
- PKCE challenge calculation
- Authorization state management for codes

**Keep**:
- Admin session management
- IndieLogin.com integration
- CSRF protection

### 3. `/home/phil/Projects/starpunk/starpunk/micropub.py`

**Current Token Verification**:
```python
from starpunk.tokens import verify_token

def handle_request():
    token_info = verify_token(bearer_token)
    if not token_info:
        return error_response("forbidden")
```

**New Token Verification**:
```python
import httpx
from flask import current_app

def verify_token(bearer_token: str) -> Optional[Dict[str, Any]]:
    """
    Verify token with external token endpoint

    Uses the configured TOKEN_ENDPOINT to validate tokens.
    Caches successful validations for 5 minutes.
    """
    # Check cache first
    cached = get_cached_token(bearer_token)
    if cached:
        return cached

    # Verify with external endpoint
    token_endpoint = current_app.config.get(
        'TOKEN_ENDPOINT',
        'https://tokens.indieauth.com/token'
    )

    try:
        response = httpx.get(
            token_endpoint,
            headers={'Authorization': f'Bearer {bearer_token}'},
            timeout=5.0
        )

        if response.status_code != 200:
            return None

        data = response.json()

        # Verify it's for our user
        if data.get('me') != current_app.config['ADMIN_ME']:
            return None

        # Verify scope
        scope = data.get('scope', '')
        if 'create' not in scope.split():
            return None

        # Cache for 5 minutes
        cache_token(bearer_token, data, ttl=300)

        return data

    except Exception as e:
        current_app.logger.error(f"Token verification failed: {e}")
        return None
```

### 4. `/home/phil/Projects/starpunk/starpunk/config.py`

**Add**:
```python
# External IndieAuth Configuration
TOKEN_ENDPOINT = os.getenv(
    'TOKEN_ENDPOINT',
    'https://tokens.indieauth.com/token'
)

# Remove internal auth endpoints
# DELETE: AUTHORIZATION_ENDPOINT
# DELETE: TOKEN_ISSUER
```

### 5. `/home/phil/Projects/starpunk/templates/base.html`

**Add to `<head>` section**:
```html
<!-- IndieAuth Discovery -->
<link rel="authorization_endpoint" href="https://indieauth.com/auth">
<link rel="token_endpoint" href="{{ config.TOKEN_ENDPOINT }}">
<link rel="micropub" href="{{ url_for('micropub.micropub_endpoint', _external=True) }}">
```

### 6. `/home/phil/Projects/starpunk/tests/test_micropub.py`

**Update token verification mocking**:
```python
@patch('starpunk.micropub.httpx.get')
def test_micropub_with_valid_token(mock_get):
    """Test Micropub with valid external token"""
    # Mock external token verification
    mock_get.return_value.status_code = 200
    mock_get.return_value.json.return_value = {
        'me': 'https://example.com',
        'client_id': 'https://quill.p3k.io',
        'scope': 'create update'
    }

    # Test Micropub request
    response = client.post(
        '/micropub',
        headers={'Authorization': 'Bearer test-token'},
        json={'type': ['h-entry'], 'properties': {'content': ['Test']}}
    )

    assert response.status_code == 201
```

## Database Migration

### Create Migration File
`/home/phil/Projects/starpunk/migrations/003_remove_indieauth_server.sql`:
```sql
-- Migration: Remove IndieAuth Server Tables
-- Description: Remove authorization_codes and tokens tables as we're using external providers
-- Date: 2025-11-24

-- Drop tokens table (depends on authorization_codes)
DROP TABLE IF EXISTS tokens;

-- Drop authorization_codes table
DROP TABLE IF EXISTS authorization_codes;

-- Remove any indexes
DROP INDEX IF EXISTS idx_tokens_hash;
DROP INDEX IF EXISTS idx_tokens_user_id;
DROP INDEX IF EXISTS idx_auth_codes_code;
DROP INDEX IF EXISTS idx_auth_codes_user_id;

-- Update schema version
UPDATE schema_version SET version = 3 WHERE id = 1;
```

## Configuration Changes

### Environment Variables

**Remove from `.env`**:
```bash
# DELETE THESE
AUTHORIZATION_ENDPOINT=/auth/authorization
TOKEN_ENDPOINT=/auth/token
TOKEN_ISSUER=https://starpunk.example.com
```

**Add to `.env`**:
```bash
# External IndieAuth Provider
TOKEN_ENDPOINT=https://tokens.indieauth.com/token
ADMIN_ME=https://your-domain.com
```

### Docker Compose

Update `docker-compose.yml` environment section:
```yaml
environment:
  - TOKEN_ENDPOINT=https://tokens.indieauth.com/token
  - ADMIN_ME=${ADMIN_ME}
  # Remove: AUTHORIZATION_ENDPOINT
  # Remove: TOKEN_ENDPOINT (internal)
```

## Import Cleanup

### Files with Import Changes

1. **Main app** (`/home/phil/Projects/starpunk/starpunk/__init__.py`):
   - Remove: `from starpunk import tokens`
   - Remove: Registration of token-related error handlers

2. **Routes init** (`/home/phil/Projects/starpunk/starpunk/routes/__init__.py`):
   - No changes needed (auth blueprint still exists)

3. **Test fixtures** (`/home/phil/Projects/starpunk/tests/conftest.py`):
   - Remove: Token creation fixtures
   - Remove: Authorization code fixtures

## Error Handling Updates

### Remove Custom Exceptions

From various files, remove:
```python
- InvalidAuthorizationCodeError
- ExpiredAuthorizationCodeError
- InvalidTokenError
- ExpiredTokenError
- InsufficientScopeError
```

### Update Error Responses

In Micropub, simplify to:
```python
if not token_info:
    return error_response("forbidden", "Invalid or expired token")
```

## Testing Updates

### Test Coverage Impact

**Before Removal**:
- ~20 test files
- ~1500 lines of test code
- Coverage: 95%

**After Removal**:
- ~15 test files
- ~1000 lines of test code
- Expected coverage: 93%

### New Test Requirements

1. **Mock External Verification**:
   ```python
   @pytest.fixture
   def mock_token_endpoint():
       with patch('starpunk.micropub.httpx.get') as mock:
           yield mock
   ```

2. **Test Scenarios**:
   - Valid token from external provider
   - Invalid token (404 from provider)
   - Wrong user (me doesn't match)
   - Insufficient scope
   - Network timeout
   - Provider unavailable

## Performance Considerations

### Token Verification Caching

Implement simple TTL cache:
```python
from functools import lru_cache
from time import time

token_cache = {}  # {token_hash: (data, expiry)}

def cache_token(token: str, data: dict, ttl: int = 300):
    token_hash = hashlib.sha256(token.encode()).hexdigest()
    token_cache[token_hash] = (data, time() + ttl)

def get_cached_token(token: str) -> Optional[dict]:
    token_hash = hashlib.sha256(token.encode()).hexdigest()
    if token_hash in token_cache:
        data, expiry = token_cache[token_hash]
        if time() < expiry:
            return data
        del token_cache[token_hash]
    return None
```

### Expected Latencies

- **Without cache**: 200-500ms per request (external API call)
- **With cache**: <1ms for cached tokens
- **Cache hit rate**: ~95% for active sessions

## Documentation Updates

### Files to Update

1. **README.md**:
   - Remove references to built-in authorization
   - Add external provider setup instructions

2. **Architecture Overview** (`/home/phil/Projects/starpunk/docs/architecture/overview.md`):
   - Update component diagram
   - Remove authorization server component
   - Clarify Micropub-only role

3. **API Documentation** (`/home/phil/Projects/starpunk/docs/api/`):
   - Remove `/auth/authorization` endpoint docs
   - Remove `/auth/token` endpoint docs
   - Update Micropub authentication section

4. **Deployment Guide** (`/home/phil/Projects/starpunk/docs/deployment/`):
   - Update environment variable list
   - Add external provider configuration

## Rollback Plan

### Emergency Rollback Script

Create `/home/phil/Projects/starpunk/scripts/rollback-auth.sh`:
```bash
#!/bin/bash
# Emergency rollback for IndieAuth removal

echo "Rolling back IndieAuth removal..."

# Restore from git
git revert HEAD~5..HEAD

# Restore database
psql $DATABASE_URL < migrations/002_secure_tokens_and_authorization_codes.sql

# Restore config
cp .env.backup .env

# Restart service
docker-compose restart

echo "Rollback complete"
```

### Verification After Rollback

1. Check endpoints respond:
   ```bash
   curl -I https://starpunk.example.com/auth/authorization
   curl -I https://starpunk.example.com/auth/token
   ```

2. Run test suite:
   ```bash
   pytest tests/test_auth.py
   pytest tests/test_tokens.py
   ```

3. Verify database tables:
   ```sql
   SELECT COUNT(*) FROM authorization_codes;
   SELECT COUNT(*) FROM tokens;
   ```

## Risk Assessment

### High Risk Areas
1. **Breaking existing tokens**: All existing tokens become invalid
2. **External dependency**: Reliance on external service availability
3. **Configuration errors**: Users may misconfigure endpoints

### Mitigation Strategies
1. **Clear communication**: Announce breaking change prominently
2. **Graceful degradation**: Cache tokens, handle timeouts
3. **Validation tools**: Provide config validation script

## Success Criteria

### Technical Criteria
- [ ] All listed files deleted
- [ ] All imports cleaned up
- [ ] Tests pass with >90% coverage
- [ ] No references to internal auth in codebase
- [ ] External verification working

### Functional Criteria
- [ ] Admin can log in
- [ ] Micropub accepts valid tokens
- [ ] Micropub rejects invalid tokens
- [ ] Discovery links present
- [ ] Documentation updated

### Performance Criteria
- [ ] Token verification <500ms
- [ ] Cache hit rate >90%
- [ ] No memory leaks from cache

## Timeline

### Day 1: Removal Phase
- Hour 1-2: Remove authorization endpoint
- Hour 3-4: Remove token endpoint
- Hour 5-6: Delete token module
- Hour 7-8: Update tests

### Day 2: Integration Phase
- Hour 1-2: Implement external verification
- Hour 3-4: Add caching layer
- Hour 5-6: Update configuration
- Hour 7-8: Test with real providers

### Day 3: Documentation Phase
- Hour 1-2: Update technical docs
- Hour 3-4: Create user guides
- Hour 5-6: Update changelog
- Hour 7-8: Final testing

## Appendix: File Size Impact

### Before Removal
```
starpunk/
  tokens.py: 8.2 KB
  routes/auth.py: 15.3 KB
  templates/auth/: 2.8 KB
tests/
  test_tokens.py: 6.1 KB
  test_routes_*.py: 12.4 KB
Total: ~45 KB
```

### After Removal
```
starpunk/
  routes/auth.py: 5.1 KB (10.2 KB removed)
  micropub.py: +1.5 KB (verification)
tests/
  test_micropub.py: +0.8 KB (mocks)
Total removed: ~40 KB
Net reduction: ~38.5 KB
```

---

**Document Version**: 1.0
**Created**: 2025-11-24
**Author**: StarPunk Architecture Team