# 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 `
` section**: ```html ``` ### 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