# IndieAuth Implementation Questions - Answered ## Quick Reference All architectural questions have been answered. This document provides the concrete guidance needed for implementation. ## Questions & Answers ### ✅ Q1: External Token Endpoint Response Format **Answer**: Follow the IndieAuth spec exactly (W3C TR). **Expected Response**: ```json { "me": "https://user.example.net/", "client_id": "https://app.example.com/", "scope": "create update delete" } ``` **Error Responses**: HTTP 400, 401, or 403 for invalid tokens. --- ### ✅ Q2: HTML Discovery Headers **Answer**: These are links users add to THEIR websites, not StarPunk. **User's HTML** (on their personal domain): ```html ``` **StarPunk's Role**: Discover these endpoints from the user's URL, don't generate them. --- ### ✅ Q3: Migration Strategy **Architectural Decision**: Keep migration 002, document it as future-use. **Action Items**: 1. Keep the migration file as-is 2. Add comment: "Tables created for future V2 internal provider support" 3. Don't use these tables in V1 (external verification only) 4. No impact on existing production databases **Rationale**: Empty tables cause no harm, avoid migration complexity later. --- ### ✅ Q4: Error Handling **Answer**: Show clear, informative error messages. **Error Messages**: - **Auth server down**: "Authorization server is unreachable. Please try again later." - **Invalid token**: "Access token is invalid or expired. Please re-authorize." - **Network error**: "Cannot connect to authorization server." **HTTP Status Codes**: - 401: No token provided - 403: Invalid/expired token - 503: Auth server unreachable --- ### ✅ Q5: Cache Revocation Delay **Architectural Decision**: Use 5-minute cache with configuration options. **Implementation**: ```python # Default: 5-minute cache MICROPUB_TOKEN_CACHE_TTL=300 MICROPUB_TOKEN_CACHE_ENABLED=true # High security: disable cache MICROPUB_TOKEN_CACHE_ENABLED=false ``` **Security Notes**: - SHA256 hash tokens before caching - Memory-only cache (not persisted) - Document 5-minute delay in security guide - Allow disabling for high-security needs --- ## Implementation Checklist ### Immediate Actions 1. **Remove Internal Provider Code**: - Delete `/auth/authorize` endpoint - Delete `/auth/token` endpoint - Remove token issuance logic - Remove authorization code generation 2. **Implement External Verification**: ```python # Core verification function def verify_micropub_token(bearer_token, expected_me): # 1. Check cache (if enabled) # 2. Discover token endpoint from expected_me # 3. Verify with external endpoint # 4. Cache result (if enabled) # 5. Return validation result ``` 3. **Add Configuration**: ```ini # Required ADMIN_ME=https://user.example.com # Optional (with defaults) MICROPUB_TOKEN_CACHE_ENABLED=true MICROPUB_TOKEN_CACHE_TTL=300 ``` 4. **Update Error Handling**: ```python try: response = httpx.get(endpoint, timeout=5.0) except httpx.TimeoutError: return error(503, "Authorization server is unreachable") ``` --- ## Code Examples ### Token Verification ```python def verify_token(bearer_token: str, token_endpoint: str, expected_me: str) -> Optional[dict]: """Verify token with external endpoint""" try: response = httpx.get( token_endpoint, headers={'Authorization': f'Bearer {bearer_token}'}, timeout=5.0 ) if response.status_code == 200: data = response.json() if data.get('me') == expected_me and 'create' in data.get('scope', ''): return data return None except httpx.TimeoutError: raise TokenEndpointError("Authorization server is unreachable") ``` ### Endpoint Discovery ```python def discover_token_endpoint(me_url: str) -> str: """Discover token endpoint from user's URL""" response = httpx.get(me_url) # 1. Check HTTP Link header if link := parse_link_header(response.headers.get('Link'), 'token_endpoint'): return urljoin(me_url, link) # 2. Check HTML tags if 'text/html' in response.headers.get('content-type', ''): if link := parse_html_link(response.text, 'token_endpoint'): return urljoin(me_url, link) raise DiscoveryError(f"No token endpoint found at {me_url}") ``` ### Micropub Endpoint ```python @app.route('/api/micropub', methods=['POST']) def micropub_endpoint(): # Extract token auth = request.headers.get('Authorization', '') if not auth.startswith('Bearer '): return {'error': 'unauthorized'}, 401 token = auth[7:] # Remove "Bearer " # Verify token try: token_info = verify_micropub_token(token, app.config['ADMIN_ME']) if not token_info: return {'error': 'forbidden'}, 403 except TokenEndpointError as e: return {'error': 'temporarily_unavailable', 'error_description': str(e)}, 503 # Process Micropub request # ... create note ... return '', 201, {'Location': note_url} ``` --- ## Testing Guide ### Manual Testing 1. Configure your domain with IndieAuth links 2. Set ADMIN_ME in StarPunk config 3. Use Quill (https://quill.p3k.io) to test posting 4. Verify token caching works (check logs) 5. Test with auth server down (block network) ### Automated Tests ```python def test_token_verification(): # Mock external token endpoint with responses.RequestsMock() as rsps: rsps.add(responses.GET, 'https://tokens.example.com/token', json={'me': 'https://user.com', 'scope': 'create'}) result = verify_token('test-token', 'https://tokens.example.com/token', 'https://user.com') assert result['me'] == 'https://user.com' def test_auth_server_unreachable(): # Mock timeout with pytest.raises(TokenEndpointError, match="unreachable"): verify_token('test-token', 'https://timeout.example.com/token', 'https://user.com') ``` --- ## User Documentation Template ### For Users: Setting Up IndieAuth 1. **Add to your website's HTML**: ```html ``` 2. **Configure StarPunk**: ```ini ADMIN_ME=https://your-website.com ``` 3. **Test with a Micropub client**: - Visit https://quill.p3k.io - Enter your website URL - Authorize and post! --- ## Summary All architectural questions have been answered: 1. **Token Format**: Follow IndieAuth spec exactly 2. **HTML Headers**: Users configure their own domains 3. **Migration**: Keep tables for future use 4. **Errors**: Clear messages about connectivity 5. **Cache**: 5-minute TTL with disable option The implementation path is clear: remove internal provider code, implement external verification with caching, and provide good error messages. This aligns with StarPunk's philosophy of minimal code and IndieWeb principles. --- **Ready for Implementation**: All questions answered, examples provided, architecture documented.