feat: Complete IndieAuth server removal (Phases 2-4)

Completed all remaining phases of ADR-030 IndieAuth provider removal.
StarPunk no longer acts as an authorization server - all IndieAuth
operations delegated to external providers.

Phase 2 - Remove Token Issuance:
- Deleted /auth/token endpoint
- Removed token_endpoint() function from routes/auth.py
- Deleted tests/test_routes_token.py

Phase 3 - Remove Token Storage:
- Deleted starpunk/tokens.py module entirely
- Created migration 004 to drop tokens and authorization_codes tables
- Deleted tests/test_tokens.py
- Removed all internal token CRUD operations

Phase 4 - External Token Verification:
- Created starpunk/auth_external.py module
- Implemented verify_external_token() for external IndieAuth providers
- Updated Micropub endpoint to use external verification
- Added TOKEN_ENDPOINT configuration
- Updated all Micropub tests to mock external verification
- HTTP timeout protection (5s) for external requests

Additional Changes:
- Created migration 003 to remove code_verifier from auth_state
- Fixed 5 migration tests that referenced obsolete code_verifier column
- Updated 11 Micropub tests for external verification
- Fixed test fixture and app context issues
- All 501 tests passing

Breaking Changes:
- Micropub clients must use external IndieAuth providers
- TOKEN_ENDPOINT configuration now required
- Existing internal tokens invalid (tables dropped)

Migration Impact:
- Simpler codebase: -500 lines of code
- Fewer database tables: -2 tables (tokens, authorization_codes)
- More secure: External providers handle token security
- More maintainable: Less authentication code to maintain

Standards Compliance:
- W3C IndieAuth specification
- OAuth 2.0 Bearer token authentication
- IndieWeb principle: delegate to external services

Related:
- ADR-030: IndieAuth Provider Removal Strategy
- ADR-050: Remove Custom IndieAuth Server
- Migration 003: Remove code_verifier from auth_state
- Migration 004: Drop tokens and authorization_codes tables

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude <noreply@anthropic.com>
This commit is contained in:
2025-11-24 17:23:46 -07:00
parent 869402ab0d
commit a3bac86647
36 changed files with 5597 additions and 2670 deletions

View File

@@ -0,0 +1,196 @@
# IndieAuth Architecture Assessment
**Date**: 2025-11-24
**Author**: StarPunk Architect
**Status**: Critical Review
## Executive Summary
You asked: **"WHY? Why not use an established provider like indieauth for authorization and token?"**
The honest answer: **The current decision to implement our own authorization and token endpoints appears to be based on a fundamental misunderstanding of how IndieAuth works, combined with over-engineering for a single-user system.**
## Current Implementation Reality
StarPunk has **already implemented** its own authorization and token endpoints:
- `/auth/authorization` - Full authorization endpoint (327 lines of code)
- `/auth/token` - Full token endpoint implementation
- Complete authorization code flow with PKCE support
- Token generation, storage, and validation
This represents significant complexity that may not have been necessary.
## The Core Misunderstanding
ADR-021 reveals the critical misunderstanding that drove this decision:
> "The user reported that IndieLogin.com requires manual client_id registration, making it unsuitable for self-hosted software"
This is **completely false**. IndieAuth (including IndieLogin.com) requires **no registration whatsoever**. Each self-hosted instance uses its own domain as the client_id automatically.
## What StarPunk Actually Needs
For a **single-user personal CMS**, StarPunk needs:
1. **Admin Authentication**: Log the owner into the admin panel
- ✅ Currently uses IndieLogin.com correctly
- Works perfectly, no changes needed
2. **Micropub Token Verification**: Verify tokens from Micropub clients
- Only needs to **verify** tokens, not issue them
- Could delegate entirely to the user's chosen authorization server
## The Architectural Options
### Option A: Use External Provider (Recommended for Simplicity)
**How it would work:**
1. User adds these links to their personal website:
```html
<link rel="authorization_endpoint" href="https://indielogin.com/auth">
<link rel="token_endpoint" href="https://tokens.indieauth.com/token">
<link rel="micropub" href="https://starpunk.example/micropub">
```
2. Micropub clients discover endpoints from user's site
3. Clients get tokens from indieauth.com/tokens.indieauth.com
4. StarPunk only verifies tokens (10-20 lines of code)
**Benefits:**
- ✅ **Simplicity**: 95% less code
- ✅ **Security**: Maintained by IndieAuth experts
- ✅ **Reliability**: Battle-tested infrastructure
- ✅ **Standards**: Full spec compliance guaranteed
- ✅ **Zero maintenance**: No security updates needed
**Drawbacks:**
- ❌ Requires user to configure their personal domain
- ❌ Dependency on external service
- ❌ User needs to understand IndieAuth flow
### Option B: Implement Own Endpoints (Current Approach)
**What we've built:**
- Complete authorization endpoint
- Complete token endpoint
- Authorization codes table
- Token management system
- PKCE support
- Scope validation
**Benefits:**
- ✅ Self-contained system
- ✅ No external dependencies for Micropub
- ✅ User doesn't need separate domain configuration
- ✅ Complete control over auth flow
**Drawbacks:**
- ❌ **Complexity**: 500+ lines of auth code
- ❌ **Security burden**: We maintain all security
- ❌ **Over-engineered**: For a single-user system
- ❌ **Spec compliance**: Our responsibility
- ❌ **Maintenance**: Ongoing updates needed
## My Honest Assessment
### Was This the Right Decision?
**No, probably not.** For a single-user personal CMS that values simplicity:
1. **We solved a problem that didn't exist** (registration requirement)
2. **We added unnecessary complexity** (500+ lines vs 20 lines)
3. **We took on security responsibilities** unnecessarily
4. **We violated our core principle**: "Every line of code must justify its existence"
### Why Did This Happen?
1. **Misunderstanding**: Believed IndieAuth required registration
2. **Scope creep**: Wanted StarPunk to be "complete"
3. **Over-engineering**: Built for theoretical multi-user future
4. **Momentum**: Once started, kept building
## What Should We Do Now?
### Option 1: Keep Current Implementation (Pragmatic)
Since it's **already built and working**:
- Document it properly
- Security audit the implementation
- Add comprehensive tests
- Accept the maintenance burden
**Rationale**: Sunk cost, but functional. Changing now adds work.
### Option 2: Simplify to External Provider (Purist)
Remove our endpoints and use external providers:
- Delete `/auth/authorization` and `/auth/token`
- Keep only admin auth via IndieLogin
- Add token verification for Micropub
- Document user setup clearly
**Rationale**: Aligns with simplicity principle, reduces attack surface.
### Option 3: Hybrid Approach (Recommended)
Keep implementation but **make it optional**:
1. Default: Use external providers (simple)
2. Advanced: Enable built-in endpoints (self-contained)
3. Configuration flag: `INDIEAUTH_MODE = "external" | "builtin"`
**Rationale**: Best of both worlds, user choice.
## My Recommendation
### For V1 Release
**Keep the current implementation** but:
1. **Document the trade-offs** clearly
2. **Add configuration option** to disable built-in endpoints
3. **Provide clear setup guides** for both modes:
- Simple mode: Use external providers
- Advanced mode: Use built-in endpoints
4. **Security audit** the implementation thoroughly
### For V2 Consideration
1. **Measure actual usage**: Do users want built-in auth?
2. **Consider removing** if external providers work well
3. **Or enhance** if users value self-contained nature
## The Real Question
You asked "WHY?" The honest answer:
**We built our own auth endpoints because we misunderstood IndieAuth and over-engineered for a single-user system. It wasn't necessary, but now that it's built, it does provide a self-contained solution that some users might value.**
## Architecture Principles Violated
1.**Minimal Code**: Added 500+ lines unnecessarily
2.**Simplicity First**: Chose complex over simple
3.**YAGNI**: Built for imagined requirements
4.**Single Responsibility**: StarPunk is a CMS, not an auth server
## Architecture Principles Upheld
1.**Standards Compliance**: Full IndieAuth spec implementation
2.**No Lock-in**: Users can switch providers
3.**Self-hostable**: Complete solution in one package
## Conclusion
The decision to implement our own authorization and token endpoints was **architecturally questionable** for a minimal single-user CMS. It adds complexity without proportional benefit.
However, since it's already implemented:
1. We should keep it for V1 (pragmatism over purity)
2. Make it optional via configuration
3. Document both approaches clearly
4. Re-evaluate based on user feedback
**The lesson**: Always challenge requirements and complexity. Just because we *can* build something doesn't mean we *should*.
---
*"Perfection is achieved not when there is nothing more to add, but when there is nothing left to take away."* - Antoine de Saint-Exupéry
This applies directly to StarPunk's auth architecture.

View File

@@ -0,0 +1,267 @@
# 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
<link rel="authorization_endpoint" href="https://indielogin.com/auth">
<link rel="token_endpoint" href="https://tokens.indieauth.com/token">
<link rel="micropub" href="https://your-starpunk.example.com/api/micropub">
```
**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 <link> 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
<link rel="authorization_endpoint" href="https://indielogin.com/auth">
<link rel="token_endpoint" href="https://tokens.indieauth.com/token">
<link rel="micropub" href="[YOUR-STARPUNK-URL]/api/micropub">
```
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.

View File

@@ -0,0 +1,469 @@
# IndieAuth Provider Removal - Implementation Guide
## Executive Summary
This document provides complete architectural guidance for removing the internal IndieAuth provider functionality from StarPunk while maintaining external IndieAuth integration for token verification. All questions have been answered based on the IndieAuth specification and architectural principles.
## Answers to Critical Questions
### Q1: External Token Endpoint Response Format ✓
**Answer**: The user is correct. The IndieAuth specification (W3C) defines exact response formats.
**Token Verification Response** (per spec section 6.3.4):
```json
{
"me": "https://user.example.net/",
"client_id": "https://app.example.com/",
"scope": "create update delete"
}
```
**Key Points**:
- Response is JSON with required fields: `me`, `client_id`, `scope`
- Additional fields may be present but should be ignored
- On invalid tokens: return HTTP 400, 401, or 403
- The `me` field MUST match the configured admin identity
### Q2: HTML Discovery Headers ✓
**Answer**: The user refers to how users configure their personal domains to point to IndieAuth providers.
**What Users Add to Their HTML** (per spec sections 4.1, 5.1, 6.1):
```html
<!-- In the <head> of the user's personal website -->
<link rel="authorization_endpoint" href="https://indielogin.com/auth">
<link rel="token_endpoint" href="https://tokens.indieauth.com/token">
<link rel="micropub" href="https://your-starpunk.example.com/api/micropub">
```
**Key Points**:
- These links go on the USER'S personal website, NOT in StarPunk
- StarPunk doesn't generate these - it discovers them from user URLs
- Users choose their own authorization/token providers
- StarPunk only needs to know the user's identity URL (configured as ADMIN_ME)
### Q3: Migration Strategy - ARCHITECTURAL DECISION
**Answer**: Keep migration 002 but clarify its purpose.
**Decision**:
1. **Keep Migration 002** - The tables are actually needed for V2 features
2. **Rename/Document** - Clarify that these tables are for future internal provider support
3. **No Production Impact** - Tables remain empty in V1, cause no harm
**Rationale**:
- The `tokens` table with secure hash storage is good future-proofing
- The `authorization_codes` table will be needed if V2 adds internal provider
- Empty tables have zero performance impact
- Removing and re-adding later creates unnecessary migration complexity
- Document clearly that these are unused in V1
**Implementation**:
```sql
-- Add comment to migration 002
-- These tables are created for future V2 internal provider support
-- In V1, StarPunk only verifies external tokens via HTTP, not database
```
### Q4: Error Handling ✓
**Answer**: The user provided clear guidance - display informative error messages.
**Error Handling Strategy**:
```python
def verify_token(bearer_token, token_endpoint):
try:
response = httpx.get(
token_endpoint,
headers={'Authorization': f'Bearer {bearer_token}'},
timeout=5.0
)
if response.status_code == 200:
return response.json()
elif response.status_code in [400, 401, 403]:
return None # Invalid token
else:
raise TokenEndpointError(f"Unexpected status: {response.status_code}")
except httpx.TimeoutError:
# User's requirement: show auth server unreachable
raise TokenEndpointError("Authorization server is unreachable")
except httpx.RequestError as e:
raise TokenEndpointError(f"Cannot connect to authorization server: {e}")
```
**User-Facing Errors**:
- **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. Check your network connection."
### Q5: Cache Revocation Delay - ARCHITECTURAL DECISION
**Answer**: The 5-minute cache is acceptable with proper configuration.
**Decision**: Use configurable short-lived cache with bypass option.
**Architecture**:
```python
class TokenCache:
"""
Simple time-based token cache with security considerations
Configuration:
- MICROPUB_TOKEN_CACHE_TTL: 300 (5 minutes default)
- MICROPUB_TOKEN_CACHE_ENABLED: true (can disable for high-security)
"""
def __init__(self, ttl=300):
self.ttl = ttl
self.cache = {} # token_hash -> (token_info, expiry_time)
def get(self, token):
"""Get cached token if valid and not expired"""
token_hash = hashlib.sha256(token.encode()).hexdigest()
if token_hash in self.cache:
info, expiry = self.cache[token_hash]
if time.time() < expiry:
return info
del self.cache[token_hash]
return None
def set(self, token, info):
"""Cache token info with TTL"""
token_hash = hashlib.sha256(token.encode()).hexdigest()
expiry = time.time() + self.ttl
self.cache[token_hash] = (info, expiry)
```
**Security Analysis**:
- **Risk**: Revoked tokens remain valid for up to 5 minutes
- **Mitigation**: Short TTL limits exposure window
- **Trade-off**: Performance vs immediate revocation
- **Best Practice**: Document the delay in security considerations
**Configuration Options**:
```ini
# For high-security environments
MICROPUB_TOKEN_CACHE_ENABLED=false # Disable cache entirely
# For normal use (recommended)
MICROPUB_TOKEN_CACHE_TTL=300 # 5 minutes
# For development/testing
MICROPUB_TOKEN_CACHE_TTL=60 # 1 minute
```
## Complete Implementation Architecture
### 1. System Boundaries
```
┌─────────────────────────────────────────────────────────────┐
│ StarPunk V1 Scope │
│ │
│ IN SCOPE: │
│ ✓ Token verification (external) │
│ ✓ Micropub endpoint │
│ ✓ Bearer token extraction │
│ ✓ Endpoint discovery │
│ ✓ Admin session auth (IndieLogin) │
│ │
│ OUT OF SCOPE: │
│ ✗ Authorization endpoint (user provides) │
│ ✗ Token endpoint (user provides) │
│ ✗ Token issuance (external only) │
│ ✗ User registration │
│ ✗ Identity management │
└─────────────────────────────────────────────────────────────┘
```
### 2. Component Design
#### 2.1 Token Verifier Component
```python
# starpunk/indieauth/verifier.py
class ExternalTokenVerifier:
"""
Verifies tokens with external IndieAuth providers
Never stores tokens, only verifies them
"""
def __init__(self, cache_ttl=300, cache_enabled=True):
self.cache = TokenCache(ttl=cache_ttl) if cache_enabled else None
self.http_client = httpx.Client(timeout=5.0)
def verify(self, bearer_token: str, expected_me: str) -> Optional[TokenInfo]:
"""
Verify bearer token with external token endpoint
Returns:
TokenInfo if valid, None if invalid
Raises:
TokenEndpointError if endpoint unreachable
"""
# Check cache first
if self.cache:
cached = self.cache.get(bearer_token)
if cached and cached.me == expected_me:
return cached
# Discover token endpoint from user's URL
token_endpoint = self.discover_token_endpoint(expected_me)
# Verify with external endpoint
token_info = self.verify_with_endpoint(
bearer_token,
token_endpoint,
expected_me
)
# Cache if valid
if token_info and self.cache:
self.cache.set(bearer_token, token_info)
return token_info
```
#### 2.2 Endpoint Discovery Component
```python
# starpunk/indieauth/discovery.py
class EndpointDiscovery:
"""
Discovers IndieAuth endpoints from user URLs
Implements full spec compliance for discovery
"""
def discover_token_endpoint(self, me_url: str) -> str:
"""
Discover token endpoint from profile URL
Priority order (per spec):
1. HTTP Link header
2. HTML <link> element
3. IndieAuth metadata endpoint
"""
response = httpx.get(me_url, follow_redirects=True)
# 1. Check HTTP Link header (highest priority)
link_header = response.headers.get('Link', '')
if endpoint := self.parse_link_header(link_header, 'token_endpoint'):
return urljoin(me_url, endpoint)
# 2. Check HTML if content-type is HTML
if 'text/html' in response.headers.get('content-type', ''):
if endpoint := self.parse_html_links(response.text, 'token_endpoint'):
return urljoin(me_url, endpoint)
# 3. Check for indieauth-metadata endpoint
if metadata_url := self.find_metadata_endpoint(response):
metadata = httpx.get(metadata_url).json()
if endpoint := metadata.get('token_endpoint'):
return endpoint
raise DiscoveryError(f"No token endpoint found at {me_url}")
```
### 3. Database Schema (V1 - Unused but Present)
```sql
-- These tables exist but are NOT USED in V1
-- They are created for future V2 internal provider support
-- Document this clearly in the migration
-- tokens table: For future internal token storage
-- authorization_codes table: For future OAuth flow support
-- V1 uses only external token verification via HTTP
-- No database queries for token validation in V1
```
### 4. API Contract
#### Micropub Endpoint
```yaml
endpoint: /api/micropub
methods: [POST]
authentication: Bearer token
request:
headers:
Authorization: "Bearer {access_token}"
Content-Type: "application/x-www-form-urlencoded" or "application/json"
body: |
Micropub create request per spec
response:
success:
status: 201
headers:
Location: "https://starpunk.example.com/notes/{id}"
unauthorized:
status: 401
body:
error: "unauthorized"
error_description: "No access token provided"
forbidden:
status: 403
body:
error: "forbidden"
error_description: "Invalid or expired access token"
server_error:
status: 503
body:
error: "temporarily_unavailable"
error_description: "Authorization server is unreachable"
```
### 5. Configuration
```ini
# config.ini or environment variables
# User's identity URL (required)
ADMIN_ME=https://user.example.com
# Token cache settings (optional)
MICROPUB_TOKEN_CACHE_ENABLED=true
MICROPUB_TOKEN_CACHE_TTL=300
# HTTP client settings (optional)
MICROPUB_HTTP_TIMEOUT=5.0
MICROPUB_MAX_RETRIES=1
```
### 6. Security Considerations
#### Token Handling
- **Never store plain tokens** - Only cache with SHA256 hashes
- **Always use HTTPS** - Token verification must use TLS
- **Validate 'me' field** - Must match configured admin identity
- **Check scope** - Ensure 'create' scope for Micropub posts
#### Cache Security
- **Short TTL** - 5 minutes maximum to limit revocation delay
- **Hash tokens** - Even in cache, never store plain tokens
- **Memory only** - Don't persist cache to disk
- **Config option** - Allow disabling cache in high-security environments
#### Error Messages
- **Don't leak tokens** - Never include tokens in error messages
- **Generic client errors** - Don't reveal why authentication failed
- **Specific server errors** - Help users understand connectivity issues
### 7. Testing Strategy
#### Unit Tests
```python
def test_token_verification():
"""Test external token verification"""
# Mock HTTP client
# Test valid token response
# Test invalid token response
# Test network errors
# Test timeout handling
def test_endpoint_discovery():
"""Test endpoint discovery from URLs"""
# Test HTTP Link header discovery
# Test HTML link element discovery
# Test metadata endpoint discovery
# Test relative URL resolution
def test_cache_behavior():
"""Test token cache"""
# Test cache hit
# Test cache miss
# Test TTL expiry
# Test cache disabled
```
#### Integration Tests
```python
def test_micropub_with_valid_token():
"""Test full Micropub flow with valid token"""
# Mock token endpoint
# Send Micropub request
# Verify note created
# Check Location header
def test_micropub_with_invalid_token():
"""Test Micropub rejection with invalid token"""
# Mock token endpoint to return 401
# Send Micropub request
# Verify 403 response
# Verify no note created
def test_micropub_with_unreachable_auth_server():
"""Test handling of unreachable auth server"""
# Mock network timeout
# Send Micropub request
# Verify 503 response
# Verify error message
```
### 8. Implementation Checklist
#### Phase 1: Remove Internal Provider
- [ ] Remove /auth/authorize endpoint
- [ ] Remove /auth/token endpoint
- [ ] Remove internal token issuance logic
- [ ] Remove authorization code generation
- [ ] Update tests to not expect these endpoints
#### Phase 2: Implement External Verification
- [ ] Create ExternalTokenVerifier class
- [ ] Implement endpoint discovery
- [ ] Add token cache with TTL
- [ ] Handle network errors gracefully
- [ ] Add configuration options
#### Phase 3: Update Documentation
- [ ] Update API documentation
- [ ] Create user setup guide
- [ ] Document security considerations
- [ ] Update architecture diagrams
- [ ] Add troubleshooting guide
#### Phase 4: Testing & Validation
- [ ] Test with IndieLogin.com
- [ ] Test with tokens.indieauth.com
- [ ] Test with real Micropub clients (Quill, Indigenous)
- [ ] Verify error handling
- [ ] Load test token verification
## Migration Path
### For Existing Installations
1. **Database**: No action needed (tables remain but unused)
2. **Configuration**: Add ADMIN_ME setting
3. **Users**: Provide setup instructions for their domains
4. **Testing**: Verify external token verification works
### For New Installations
1. **Fresh start**: Full V1 external-only implementation
2. **Simple setup**: Just configure ADMIN_ME
3. **User guide**: How to configure their domain for IndieAuth
## Conclusion
This architecture provides a clean, secure, and standards-compliant implementation of external IndieAuth token verification. The design follows the principle of "every line of code must justify its existence" by removing unnecessary internal provider complexity while maintaining full Micropub support.
The key insight is that StarPunk is a **Micropub server**, not an **authorization server**. This separation of concerns aligns perfectly with IndieWeb principles and keeps the codebase minimal and focused.
---
**Document Version**: 1.0
**Created**: 2024-11-24
**Author**: StarPunk Architecture Team
**Status**: Final

View File

@@ -0,0 +1,593 @@
# IndieAuth Removal: Phased Implementation Guide
## Overview
This document breaks down the IndieAuth server removal into testable phases, each with clear acceptance criteria and verification steps.
## Phase 1: Remove Authorization Server (4 hours)
### Objective
Remove the authorization endpoint and consent UI while keeping the system functional.
### Tasks
#### 1.1 Remove Authorization UI (30 min)
```bash
# Delete consent template
rm /home/phil/Projects/starpunk/templates/auth/authorize.html
# Verify
ls /home/phil/Projects/starpunk/templates/auth/
# Should be empty or not exist
```
#### 1.2 Remove Authorization Endpoint (1 hour)
In `/home/phil/Projects/starpunk/starpunk/routes/auth.py`:
- Delete `authorization_endpoint()` function
- Delete related imports from `starpunk.tokens`
- Keep admin auth routes intact
#### 1.3 Remove Authorization Tests (30 min)
```bash
# Delete test files
rm /home/phil/Projects/starpunk/tests/test_routes_authorization.py
rm /home/phil/Projects/starpunk/tests/test_auth_pkce.py
```
#### 1.4 Remove PKCE Implementation (1 hour)
From `/home/phil/Projects/starpunk/starpunk/auth.py`:
- Remove `generate_code_verifier()`
- Remove `calculate_code_challenge()`
- Remove PKCE validation logic
- Keep session management functions
#### 1.5 Update Route Registration (30 min)
Ensure no references to `/auth/authorization` in:
- URL route definitions
- Template URL generation
- Documentation
### Acceptance Criteria
**Server Starts Successfully**
```bash
uv run python -m starpunk
# No import errors or missing route errors
```
**Admin Login Works**
```bash
# Navigate to /admin/login
# Can still authenticate via IndieLogin.com
# Session created successfully
```
**No Authorization Endpoint**
```bash
curl -I http://localhost:5000/auth/authorization
# Should return 404 Not Found
```
**Tests Pass (Remaining)**
```bash
uv run pytest tests/ -k "not authorization and not pkce"
# All remaining tests pass
```
### Verification Commands
```bash
# Check for orphaned imports
grep -r "authorization_endpoint" /home/phil/Projects/starpunk/
# Should return nothing
# Check for PKCE references
grep -r "code_challenge\|code_verifier" /home/phil/Projects/starpunk/
# Should only appear in migration files or comments
```
---
## Phase 2: Remove Token Issuance (3 hours)
### Objective
Remove token generation and issuance while keeping token verification temporarily.
### Tasks
#### 2.1 Remove Token Endpoint (1 hour)
In `/home/phil/Projects/starpunk/starpunk/routes/auth.py`:
- Delete `token_endpoint()` function
- Remove token-related imports
#### 2.2 Remove Token Generation (1 hour)
In `/home/phil/Projects/starpunk/starpunk/tokens.py`:
- Remove `create_access_token()`
- Remove `create_authorization_code()`
- Remove `exchange_authorization_code()`
- Keep `verify_token()` temporarily (will modify in Phase 4)
#### 2.3 Remove Token Tests (30 min)
```bash
rm /home/phil/Projects/starpunk/tests/test_routes_token.py
rm /home/phil/Projects/starpunk/tests/test_tokens.py
```
#### 2.4 Clean Up Exceptions (30 min)
Remove custom exceptions:
- `InvalidAuthorizationCodeError`
- `ExpiredAuthorizationCodeError`
- Update error handling to use generic exceptions
### Acceptance Criteria
**No Token Endpoint**
```bash
curl -I http://localhost:5000/auth/token
# Should return 404 Not Found
```
**No Token Generation Code**
```bash
grep -r "create_access_token\|create_authorization_code" /home/phil/Projects/starpunk/starpunk/
# Should return nothing (except in comments)
```
**Server Still Runs**
```bash
uv run python -m starpunk
# No import errors
```
**Micropub Temporarily Broken (Expected)**
```bash
# This is expected and will be fixed in Phase 4
# Document that Micropub is non-functional during migration
```
### Verification Commands
```bash
# Check for token generation references
grep -r "generate_token\|issue_token" /home/phil/Projects/starpunk/
# Should be empty
# Verify exception cleanup
grep -r "InvalidAuthorizationCodeError" /home/phil/Projects/starpunk/
# Should be empty
```
---
## Phase 3: Database Schema Simplification (2 hours)
### Objective
Remove authorization and token tables from the database.
### Tasks
#### 3.1 Create Removal Migration (30 min)
Create `/home/phil/Projects/starpunk/migrations/003_remove_indieauth_tables.sql`:
```sql
-- Remove IndieAuth server tables
BEGIN TRANSACTION;
-- Drop dependent objects first
DROP INDEX IF EXISTS idx_tokens_hash;
DROP INDEX IF EXISTS idx_tokens_user_id;
DROP INDEX IF EXISTS idx_tokens_client_id;
DROP INDEX IF EXISTS idx_auth_codes_code;
DROP INDEX IF EXISTS idx_auth_codes_user_id;
-- Drop tables
DROP TABLE IF EXISTS tokens CASCADE;
DROP TABLE IF EXISTS authorization_codes CASCADE;
-- Clean up any orphaned sequences
DROP SEQUENCE IF EXISTS tokens_id_seq;
DROP SEQUENCE IF EXISTS authorization_codes_id_seq;
COMMIT;
```
#### 3.2 Run Migration (30 min)
```bash
# Backup database first
pg_dump $DATABASE_URL > backup_before_removal.sql
# Run migration
uv run python -m starpunk.migrate
```
#### 3.3 Update Schema Documentation (30 min)
Update `/home/phil/Projects/starpunk/docs/design/database-schema.md`:
- Remove token table documentation
- Remove authorization_codes table documentation
- Update ER diagram
#### 3.4 Remove Old Migration (30 min)
```bash
# Archive old migration
mv /home/phil/Projects/starpunk/migrations/002_secure_tokens_and_authorization_codes.sql \
/home/phil/Projects/starpunk/migrations/archive/
```
### Acceptance Criteria
**Tables Removed**
```sql
-- Connect to database and verify
\dt
-- Should NOT list 'tokens' or 'authorization_codes'
```
**No Foreign Key Errors**
```sql
-- Check for orphaned constraints
SELECT conname FROM pg_constraint
WHERE conname LIKE '%token%' OR conname LIKE '%auth%';
-- Should return minimal results (only auth_state related)
```
**Application Starts**
```bash
uv run python -m starpunk
# No database connection errors
```
**Admin Functions Work**
- Can log in
- Can create posts
- Sessions persist
### Rollback Plan
```bash
# If issues arise
psql $DATABASE_URL < backup_before_removal.sql
# Re-run old migration
psql $DATABASE_URL < /home/phil/Projects/starpunk/migrations/archive/002_secure_tokens_and_authorization_codes.sql
```
---
## Phase 4: External Token Verification (4 hours)
### Objective
Replace internal token verification with external provider verification.
### Tasks
#### 4.1 Implement External Verification (2 hours)
Create new verification in `/home/phil/Projects/starpunk/starpunk/micropub.py`:
```python
import hashlib
import httpx
from typing import Optional, Dict, Any
from flask import current_app
# Simple in-memory cache
_token_cache = {}
def verify_token(bearer_token: str) -> Optional[Dict[str, Any]]:
"""Verify token with external endpoint"""
# Check cache
token_hash = hashlib.sha256(bearer_token.encode()).hexdigest()
if token_hash in _token_cache:
data, expiry = _token_cache[token_hash]
if time.time() < expiry:
return data
del _token_cache[token_hash]
# Verify with external endpoint
endpoint = current_app.config.get('TOKEN_ENDPOINT')
if not endpoint:
return None
try:
response = httpx.get(
endpoint,
headers={'Authorization': f'Bearer {bearer_token}'},
timeout=5.0
)
if response.status_code != 200:
return None
data = response.json()
# Validate response
if data.get('me') != current_app.config.get('ADMIN_ME'):
return None
if 'create' not in data.get('scope', '').split():
return None
# Cache for 5 minutes
_token_cache[token_hash] = (data, time.time() + 300)
return data
except Exception as e:
current_app.logger.error(f"Token verification failed: {e}")
return None
```
#### 4.2 Update Configuration (30 min)
In `/home/phil/Projects/starpunk/starpunk/config.py`:
```python
# External IndieAuth settings
TOKEN_ENDPOINT = os.getenv('TOKEN_ENDPOINT', 'https://tokens.indieauth.com/token')
ADMIN_ME = os.getenv('ADMIN_ME') # Required
# Validate configuration
if not ADMIN_ME:
raise ValueError("ADMIN_ME must be configured")
```
#### 4.3 Remove Old Token Module (30 min)
```bash
rm /home/phil/Projects/starpunk/starpunk/tokens.py
```
#### 4.4 Update Tests (1 hour)
Update `/home/phil/Projects/starpunk/tests/test_micropub.py`:
```python
@patch('starpunk.micropub.httpx.get')
def test_external_token_verification(mock_get):
mock_response = Mock()
mock_response.status_code = 200
mock_response.json.return_value = {
'me': 'https://example.com',
'scope': 'create update'
}
mock_get.return_value = mock_response
# Test verification
result = verify_token('test-token')
assert result is not None
assert result['me'] == 'https://example.com'
```
### Acceptance Criteria
**External Verification Works**
```bash
# With a valid token from tokens.indieauth.com
curl -X POST http://localhost:5000/micropub \
-H "Authorization: Bearer VALID_TOKEN" \
-H "Content-Type: application/json" \
-d '{"type": ["h-entry"], "properties": {"content": ["Test"]}}'
# Should return 201 Created
```
**Invalid Tokens Rejected**
```bash
curl -X POST http://localhost:5000/micropub \
-H "Authorization: Bearer INVALID_TOKEN" \
-H "Content-Type: application/json" \
-d '{"type": ["h-entry"], "properties": {"content": ["Test"]}}'
# Should return 403 Forbidden
```
**Token Caching Works**
```python
# In test environment
token = "test-token"
result1 = verify_token(token) # External call
result2 = verify_token(token) # Should use cache
# Verify only one external call made
```
**Configuration Validated**
```bash
# Without ADMIN_ME set
unset ADMIN_ME
uv run python -m starpunk
# Should fail with clear error message
```
### Performance Verification
```bash
# Measure token verification time
time curl -X GET http://localhost:5000/micropub \
-H "Authorization: Bearer VALID_TOKEN" \
-w "\nTime: %{time_total}s\n"
# First call: <500ms
# Cached calls: <50ms
```
---
## Phase 5: Documentation and Discovery (2 hours)
### Objective
Update all documentation and add proper IndieAuth discovery headers.
### Tasks
#### 5.1 Add Discovery Links (30 min)
In `/home/phil/Projects/starpunk/templates/base.html`:
```html
<head>
<!-- Existing head content -->
<!-- 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) }}">
</head>
```
#### 5.2 Update User Documentation (45 min)
Create `/home/phil/Projects/starpunk/docs/user-guide/indieauth-setup.md`:
```markdown
# Setting Up IndieAuth for StarPunk
## Quick Start
1. Add these links to your personal website's HTML:
```html
<link rel="authorization_endpoint" href="https://indieauth.com/auth">
<link rel="token_endpoint" href="https://tokens.indieauth.com/token">
<link rel="micropub" href="https://your-starpunk.com/micropub">
```
2. Configure StarPunk:
```ini
ADMIN_ME=https://your-website.com
TOKEN_ENDPOINT=https://tokens.indieauth.com/token
```
3. Use any Micropub client!
```
#### 5.3 Update README (15 min)
- Remove references to built-in authorization
- Add "Prerequisites" section about external IndieAuth
- Update configuration examples
#### 5.4 Update CHANGELOG (15 min)
```markdown
## [0.5.0] - 2025-11-24
### BREAKING CHANGES
- Removed built-in IndieAuth authorization server
- Removed token issuance functionality
- All existing tokens are invalidated
### Changed
- Token verification now uses external IndieAuth providers
- Simplified database schema (removed token tables)
- Reduced codebase by ~500 lines
### Added
- Support for external token endpoints
- Token verification caching for performance
- IndieAuth discovery links in HTML
### Migration Guide
Users must now:
1. Configure external IndieAuth provider
2. Re-authenticate with Micropub clients
3. Update ADMIN_ME configuration
```
#### 5.5 Version Bump (15 min)
Update `/home/phil/Projects/starpunk/starpunk/__init__.py`:
```python
__version__ = "0.5.0" # Breaking change per versioning strategy
```
### Acceptance Criteria
**Discovery Links Present**
```bash
curl http://localhost:5000/ | grep -E "authorization_endpoint|token_endpoint|micropub"
# Should show all three link tags
```
**Documentation Complete**
- [ ] User guide explains external provider setup
- [ ] README reflects new architecture
- [ ] CHANGELOG documents breaking changes
- [ ] Migration guide provided
**Version Updated**
```bash
uv run python -c "import starpunk; print(starpunk.__version__)"
# Should output: 0.5.0
```
**Examples Work**
- [ ] Example configuration in docs is valid
- [ ] HTML snippet in docs is correct
- [ ] Micropub client setup instructions tested
---
## Final Validation Checklist
### System Health
- [ ] Server starts without errors
- [ ] Admin can log in
- [ ] Admin can create posts
- [ ] Micropub endpoint responds
- [ ] Valid tokens accepted
- [ ] Invalid tokens rejected
- [ ] HTML has discovery links
### Code Quality
- [ ] No orphaned imports
- [ ] No references to removed code
- [ ] Tests pass with >90% coverage
- [ ] No security warnings
### Performance
- [ ] Token verification <500ms
- [ ] Cached verification <50ms
- [ ] Memory usage stable
- [ ] No database deadlocks
### Documentation
- [ ] Architecture docs updated
- [ ] User guide complete
- [ ] API docs accurate
- [ ] CHANGELOG updated
- [ ] Version bumped
### Database
- [ ] Old tables removed
- [ ] No orphaned constraints
- [ ] Migration successful
- [ ] Backup available
## Rollback Decision Tree
```
Issue Detected?
├─ During Phase 1-2?
│ └─ Git revert commits
│ └─ Restart server
├─ During Phase 3?
│ └─ Restore database backup
│ └─ Git revert commits
│ └─ Restart server
└─ During Phase 4-5?
└─ Critical issue?
├─ Yes: Full rollback
│ └─ Restore DB + revert code
└─ No: Fix forward
└─ Patch issue
└─ Continue deployment
```
## Success Metrics
### Quantitative
- **Lines removed**: >500
- **Test coverage**: >90%
- **Token verification**: <500ms
- **Cache hit rate**: >90%
- **Memory stable**: <100MB
### Qualitative
- **Simpler architecture**: Clear separation of concerns
- **Better security**: Specialized providers handle auth
- **Less maintenance**: No auth code to maintain
- **User flexibility**: Choice of providers
- **Standards compliant**: Pure Micropub server
## Risk Matrix
| Risk | Probability | Impact | Mitigation |
|------|------------|---------|------------|
| Breaking existing tokens | Certain | Medium | Clear communication, migration guide |
| External service down | Low | High | Token caching, timeout handling |
| User confusion | Medium | Low | Comprehensive documentation |
| Performance degradation | Low | Medium | Caching layer, monitoring |
| Security vulnerability | Low | High | Use established providers |
---
**Document Version**: 1.0
**Created**: 2025-11-24
**Author**: StarPunk Architecture Team
**Status**: Ready for Implementation

View File

@@ -0,0 +1,529 @@
# 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

View File

@@ -0,0 +1,240 @@
# Phase 1 Completion Guide: Test Cleanup and Commit
## Architectural Decision Summary
After reviewing your Phase 1 implementation, I've made the following architectural decisions:
### 1. Implementation Assessment: ✅ EXCELLENT
Your Phase 1 implementation is correct and complete. You've successfully:
- Removed the authorization endpoint cleanly
- Preserved admin functionality
- Documented everything properly
- Identified all test impacts
### 2. Test Strategy: DELETE ALL 30 FAILING TESTS NOW
**Rationale**: These tests are testing removed functionality. Keeping them provides no value and creates confusion.
### 3. Phase Strategy: ACCELERATE WITH COMBINED PHASES
After completing Phase 1, combine Phases 2+3 for faster delivery.
## Immediate Actions Required (30 minutes)
### Step 1: Analyze Failing Tests (5 minutes)
First, let's identify exactly which tests to remove:
```bash
# Get a clean list of failing test locations
uv run pytest --tb=no -q 2>&1 | grep "FAILED" | cut -d':' -f1-3 | sort -u
```
### Step 2: Remove OAuth Metadata Tests (5 minutes)
Edit `/home/phil/Projects/starpunk/tests/test_routes_public.py`:
**Delete these entire test classes**:
- `TestOAuthMetadataEndpoint` (all 10 tests)
- `TestIndieAuthMetadataLink` (all 3 tests)
These tested the `/.well-known/oauth-authorization-server` endpoint which no longer exists.
### Step 3: Handle State Token Tests (10 minutes)
Edit `/home/phil/Projects/starpunk/tests/test_auth.py`:
**Critical**: Some state token tests might be for admin login. Check each one:
```python
# If test references authorization flow -> DELETE
# If test references admin login -> KEEP AND FIX
```
Tests to review:
- `test_verify_valid_state_token` - Check if this is admin login
- `test_verify_invalid_state_token` - Check if this is admin login
- `test_verify_expired_state_token` - Check if this is admin login
- `test_state_tokens_are_single_use` - Check if this is admin login
- `test_initiate_login_success` - Likely admin login, may need fixing
- `test_handle_callback_*` - Check each for admin vs authorization
**Decision Logic**:
- If the test is validating state tokens for admin login via IndieLogin.com -> FIX IT
- If the test is validating state tokens for Micropub authorization -> DELETE IT
### Step 4: Fix Migration Tests (5 minutes)
Edit `/home/phil/Projects/starpunk/tests/test_migrations.py`:
For these two tests:
- `test_is_schema_current_with_code_verifier`
- `test_run_migrations_fresh_database`
**Action**: Remove any assertions about `code_verifier` or `code_challenge` columns. These PKCE fields are gone.
### Step 5: Remove Client Discovery Tests (2 minutes)
Edit `/home/phil/Projects/starpunk/tests/test_templates.py`:
**Delete the entire class**: `TestIndieAuthClientDiscovery`
This tested h-app microformats for Micropub client discovery, which is no longer relevant.
### Step 6: Fix Dev Auth Test (3 minutes)
Edit `/home/phil/Projects/starpunk/tests/test_routes_dev_auth.py`:
The test `test_dev_mode_requires_dev_admin_me` is failing. Investigate why and fix or remove based on current functionality.
## Verification Commands
After making changes:
```bash
# Run tests to verify all pass
uv run pytest
# Expected output:
# =============== XXX passed in X.XXs ===============
# (No failures!)
# Count remaining tests
uv run pytest --co -q | wc -l
# Should be around 539 tests (down from 569)
```
## Git Commit Strategy
### Commit 1: Test Cleanup
```bash
git add tests/
git commit -m "test: Remove tests for deleted IndieAuth authorization functionality
- Remove OAuth metadata endpoint tests (13 tests)
- Remove authorization-specific state token tests
- Remove authorization callback tests
- Remove h-app client discovery tests (5 tests)
- Update migration tests to match current schema
All removed tests validated functionality that was intentionally
deleted in Phase 1 of the IndieAuth removal plan.
Test suite now: 100% passing"
```
### Commit 2: Phase 1 Implementation
```bash
git add .
git commit -m "feat!: Phase 1 - Remove IndieAuth authorization server
BREAKING CHANGE: Removed built-in IndieAuth authorization endpoint
Removed:
- /auth/authorization endpoint and handler
- Authorization consent UI template
- Authorization-related imports and functions
- PKCE implementation tests
Preserved:
- Admin login via IndieLogin.com
- Session management
- Token endpoint (for Phase 2 removal)
This completes Phase 1 of 5 in the IndieAuth removal plan.
Version: 1.0.0-rc.4
Refs: ADR-050, ADR-051
Docs: docs/architecture/indieauth-removal-phases.md
Report: docs/reports/2025-11-24-phase1-indieauth-server-removal.md"
```
### Commit 3: Architecture Documentation
```bash
git add docs/
git commit -m "docs: Add architecture decisions and reports for Phase 1
- ADR-051: Test strategy and implementation review
- Phase 1 completion guide
- Implementation reports
These document the architectural decisions made during
Phase 1 implementation and provide guidance for remaining phases."
```
## Decision Points During Cleanup
### For State Token Tests
Ask yourself:
1. Does this test verify state tokens for `/auth/callback` (admin login)?
- **YES** → Fix the test to work with current code
- **NO** → Delete it
2. Does the test reference authorization codes or Micropub clients?
- **YES** → Delete it
- **NO** → Keep and fix
### For Callback Tests
Ask yourself:
1. Is this testing the IndieLogin.com callback for admin?
- **YES** → Fix it
- **NO** → Delete it
2. Does it reference authorization approval/denial?
- **YES** → Delete it
- **NO** → Keep and fix
## Success Criteria
You'll know Phase 1 is complete when:
1. ✅ All tests pass (100% green)
2. ✅ No references to authorization endpoint in tests
3. ✅ Admin login tests still present and passing
4. ✅ Clean git commits with clear messages
5. ✅ Documentation updated
## Next Steps: Combined Phase 2+3
After committing Phase 1, immediately proceed with:
1. **Phase 2+3 Combined** (2 hours):
- Remove `/auth/token` endpoint
- Delete `starpunk/tokens.py` entirely
- Create database migration to drop tables
- Remove all token-related tests
- Version: 1.0.0-rc.5
2. **Phase 4** (2 hours):
- Implement external token verification
- Add caching layer
- Update Micropub to use external verification
- Version: 1.0.0-rc.6
3. **Phase 5** (1 hour):
- Add discovery links
- Update all documentation
- Final version: 1.0.0
## Architecture Principles Maintained
Throughout this cleanup:
- **Simplicity First**: Remove complexity, don't reorganize it
- **Clean States**: No partially-broken states
- **Clear Intent**: Deleted code is better than commented code
- **Test Confidence**: Green tests or no tests, never red tests
## Questions?
If you encounter any test that you're unsure about:
1. Check if it tests admin functionality (keep/fix)
2. Check if it tests authorization functionality (delete)
3. When in doubt, trace the code path it's testing
Remember: We're removing an entire subsystem. It's better to be thorough than cautious.
---
**Time Estimate**: 30 minutes
**Complexity**: Low
**Risk**: Minimal (tests only)
**Confidence**: High - clear architectural decision

View File

@@ -0,0 +1,428 @@
# StarPunk Simplified Authentication Architecture
## Overview
After removing the custom IndieAuth authorization server, StarPunk becomes a pure Micropub server that relies on external providers for all authentication and authorization.
## Architecture Diagrams
### Before: Complex Mixed-Mode Architecture
```
┌──────────────────────────────────────────────────────────────┐
│ StarPunk Instance │
│ │
│ ┌────────────────────────────────────────────────────────┐ │
│ │ Web Interface │ │
│ │ ┌─────────────┐ ┌──────────────┐ ┌──────────────┐ │ │
│ │ │ Admin Login │ │ Authorization │ │ Token Issuer │ │ │
│ │ └─────────────┘ └──────────────┘ └──────────────┘ │ │
│ └────────────────────────────────────────────────────────┘ │
│ │
│ ┌────────────────────────────────────────────────────────┐ │
│ │ Auth Module │ │
│ │ ┌──────────┐ ┌──────────┐ ┌──────────┐ ┌──────────┐ │ │
│ │ │ Sessions │ │ PKCE │ │ Tokens │ │ Codes │ │ │
│ │ └──────────┘ └──────────┘ └──────────┘ └──────────┘ │ │
│ └────────────────────────────────────────────────────────┘ │
│ │
│ ┌────────────────────────────────────────────────────────┐ │
│ │ Database │ │
│ │ ┌────────┐ ┌──────────────────┐ ┌─────────────────┐ │ │
│ │ │ Users │ │ authorization_codes│ │ tokens │ │ │
│ │ └────────┘ └──────────────────┘ └─────────────────┘ │ │
│ └────────────────────────────────────────────────────────┘ │
└──────────────────────────────────────────────────────────────┘
Problems:
- 500+ lines of security-critical code
- Dual role: authorization server AND resource server
- Complex token lifecycle management
- Database bloat with token storage
- Maintenance burden for security updates
```
### After: Clean Separation of Concerns
```
┌──────────────────────────────────────────────────────────────┐
│ StarPunk Instance │
│ │
│ ┌────────────────────────────────────────────────────────┐ │
│ │ Web Interface │ │
│ │ ┌─────────────┐ ┌──────────────┐ │ │
│ │ │ Admin Login │ │ Micropub │ │ │
│ │ └─────────────┘ └──────────────┘ │ │
│ └────────────────────────────────────────────────────────┘ │
│ │
│ ┌────────────────────────────────────────────────────────┐ │
│ │ Auth Module │ │
│ │ ┌──────────────┐ ┌──────────────────────┐ │ │
│ │ │ Sessions │ │ Token Verification │ │ │
│ │ │ (Admin Only) │ │ (External Provider) │ │ │
│ │ └──────────────┘ └──────────────────────┘ │ │
│ └────────────────────────────────────────────────────────┘ │
│ │
│ ┌────────────────────────────────────────────────────────┐ │
│ │ Database │ │
│ │ ┌────────┐ ┌──────────┐ ┌─────────┐ │ │
│ │ │ Users │ │auth_state│ │ posts │ (No token tables)│ │
│ │ └────────┘ └──────────┘ └─────────┘ │ │
│ └────────────────────────────────────────────────────────┘ │
└──────────────────────────────────────────────────────────────┘
│ API Calls
┌──────────────────────────────────────────────────────────────┐
│ External IndieAuth Providers │
│ ┌─────────────────────┐ ┌─────────────────────────┐ │
│ │ indieauth.com │ │ tokens.indieauth.com │ │
│ │ (Authorization) │ │ (Token Verification) │ │
│ └─────────────────────┘ └─────────────────────────┘ │
└──────────────────────────────────────────────────────────────┘
Benefits:
- 500+ lines of code removed
- Clear single responsibility
- No security burden
- Minimal database footprint
- Zero maintenance for auth code
```
## Authentication Flows
### Flow 1: Admin Authentication (Unchanged)
```
Admin User StarPunk IndieLogin.com
│ │ │
├──── GET /admin/login ───→ │ │
│ │ │
│ ←── Login Form ─────────── │ │
│ │ │
├──── POST /auth/login ───→ │ │
│ (me=admin.com) │ │
│ ├──── Redirect ──────────────→ │
│ │ (client_id=starpunk.com) │
│ ←──────────── Authorization Request ───────────────────── │
│ │ │
├───────────── Authenticate with IndieLogin ──────────────→ │
│ │ │
│ │ ←── Callback ────────────────│
│ │ (me=admin.com) │
│ │ │
│ ←── Session Cookie ─────── │ │
│ │ │
│ Admin Access │ │
```
### Flow 2: Micropub Client Authentication (Simplified)
```
Micropub Client StarPunk External Token Endpoint
│ │ │
├─── POST /micropub ───→ │ │
│ Bearer: token123 │ │
│ ├──── GET /token ─────────→ │
│ │ Bearer: token123 │
│ │ │
│ │ ←── Token Info ──────────│
│ │ {me, scope, client_id} │
│ │ │
│ │ [Validate me==ADMIN_ME] │
│ │ [Check scope includes │
│ │ "create"] │
│ │ │
│ ←── 201 Created ────────│ │
│ Location: /post/123 │ │
```
## Component Responsibilities
### StarPunk Components
#### 1. Admin Authentication (`/auth/*`)
**Responsibility**: Manage admin sessions via IndieLogin.com
**Does**:
- Initiate OAuth flow with IndieLogin.com
- Validate callback and create session
- Manage session lifecycle
**Does NOT**:
- Issue tokens
- Store passwords
- Manage user identities
#### 2. Micropub Endpoint (`/micropub`)
**Responsibility**: Accept and process Micropub requests
**Does**:
- Extract Bearer tokens from requests
- Verify tokens with external endpoint
- Create/update/delete posts
- Return proper Micropub responses
**Does NOT**:
- Issue tokens
- Manage authorization codes
- Store token data
#### 3. Token Verification Module
**Responsibility**: Validate tokens with external providers
**Does**:
- Call external token endpoint
- Cache valid tokens (5 min TTL)
- Validate scope and identity
**Does NOT**:
- Generate tokens
- Store tokens permanently
- Manage token lifecycle
### External Provider Responsibilities
#### indieauth.com
- User authentication
- Authorization consent
- Authorization code generation
- Profile discovery
#### tokens.indieauth.com
- Token issuance
- Token verification
- Token revocation
- Scope management
## Configuration
### Required Settings
```ini
# Identity of the admin user
ADMIN_ME=https://your-domain.com
# External token endpoint for verification
TOKEN_ENDPOINT=https://tokens.indieauth.com/token
# Admin session secret (existing)
SECRET_KEY=your-secret-key
```
### HTML Discovery
```html
<!-- Added to all pages -->
<link rel="authorization_endpoint" href="https://indieauth.com/auth">
<link rel="token_endpoint" href="https://tokens.indieauth.com/token">
<link rel="micropub" href="https://starpunk.example.com/micropub">
```
## Security Model
### Trust Boundaries
```
┌─────────────────────────────────────────────────────────────┐
│ Trusted Zone │
│ ┌──────────────────────────────────────────────────────┐ │
│ │ StarPunk Application │ │
│ │ - Session management │ │
│ │ - Post creation/management │ │
│ │ - Admin interface │ │
│ └──────────────────────────────────────────────────────┘ │
└─────────────────────────────────────────────────────────────┘
Token Verification API
┌─────────────────────────────────────────────────────────────┐
│ Semi-Trusted Zone │
│ ┌──────────────────────────────────────────────────────┐ │
│ │ External IndieAuth Providers │ │
│ │ - Token validation │ │
│ │ - Identity verification │ │
│ └──────────────────────────────────────────────────────┘ │
└─────────────────────────────────────────────────────────────┘
User Authentication
┌─────────────────────────────────────────────────────────────┐
│ Untrusted Zone │
│ ┌──────────────────────────────────────────────────────┐ │
│ │ Micropub Clients │ │
│ │ - Must provide valid Bearer tokens │ │
│ │ - Tokens verified on every request │ │
│ └──────────────────────────────────────────────────────┘ │
└─────────────────────────────────────────────────────────────┘
```
### Security Benefits of Simplified Architecture
1. **Reduced Attack Surface**
- No token generation = no cryptographic mistakes
- No token storage = no database leaks
- No PKCE = no implementation errors
2. **Specialized Security**
- Auth providers focus solely on security
- Regular updates from specialized teams
- Community-vetted implementations
3. **Clear Boundaries**
- StarPunk only verifies, never issues
- Single source of truth (external provider)
- No confused deputy problems
## Performance Characteristics
### Token Verification Performance
```
Without Cache:
┌──────────┐ 200-500ms ┌─────────────┐
│ Micropub ├───────────────────→│Token Endpoint│
└──────────┘ └─────────────┘
With Cache (95% hit rate):
┌──────────┐ <1ms ┌─────────────┐
│ Micropub ├───────────────────→│ Memory Cache │
└──────────┘ └─────────────┘
```
### Cache Strategy
```python
Cache Key: SHA256(token)
Cache Value: {
'me': 'https://user.com',
'client_id': 'https://client.com',
'scope': 'create update delete',
'expires_at': timestamp + 300 # 5 minutes
}
```
### Expected Latencies
- First request: 200-500ms (external API)
- Cached request: <1ms
- Admin login: 1-2s (OAuth flow)
- Post creation: <50ms (after auth)
## Migration Impact
### Breaking Changes
1. **All existing tokens invalid**
- Users must re-authenticate
- No migration path for tokens
2. **Endpoint removal**
- `/auth/authorization` → 404
- `/auth/token` → 404
3. **Configuration required**
- Must set `ADMIN_ME`
- Must configure domain with IndieAuth links
### Non-Breaking Preserved Functionality
1. **Admin login unchanged**
- Same URL (`/admin/login`)
- Same provider (IndieLogin.com)
- Sessions preserved
2. **Micropub API unchanged**
- Same endpoint (`/micropub`)
- Same request format
- Same response format
## Comparison with Other Systems
### WordPress + IndieAuth Plugin
- **Similarity**: External provider for auth
- **Difference**: WP has user management, we don't
### Known IndieWeb Sites
- **micro.blog**: Custom auth server (complex)
- **Indigenous**: Client only, uses external auth
- **StarPunk**: Micropub server only (simple)
### Architecture Philosophy
```
"Do one thing well"
├── StarPunk: Publish notes
├── IndieAuth.com: Authenticate users
└── Tokens.indieauth.com: Manage tokens
```
## Future Considerations
### Potential V2 Enhancements (NOT for V1)
1. **Multi-user support**
- Would require user management
- Still use external auth
2. **Multiple token endpoints**
- Support different providers per user
- Endpoint discovery from user domain
3. **Token caching layer**
- Redis for distributed caching
- Longer TTL with refresh
### Explicitly NOT Implementing
1. **Custom authorization server**
- Violates simplicity principle
- Maintenance burden
2. **Password authentication**
- Not IndieWeb compliant
- Security burden
3. **JWT validation**
- Not part of IndieAuth spec
- Unnecessary complexity
## Testing Strategy
### Unit Tests
```python
# Test external verification
@patch('httpx.get')
def test_token_verification(mock_get):
# Mock successful response
mock_get.return_value.status_code = 200
mock_get.return_value.json.return_value = {
'me': 'https://example.com',
'scope': 'create'
}
result = verify_token('test-token')
assert result is not None
```
### Integration Tests
```python
# Test with real endpoint (in CI)
def test_real_token_verification():
# Use test token from tokens.indieauth.com
token = get_test_token()
result = verify_token(token)
assert result['me'] == TEST_USER
```
### Manual Testing
1. Configure domain with IndieAuth links
2. Use Quill or Indigenous
3. Create test post
4. Verify token caching
## Metrics for Success
### Quantitative Metrics
- **Code removed**: >500 lines
- **Database tables removed**: 2
- **Complexity reduction**: ~40%
- **Test coverage maintained**: >90%
- **Performance**: <500ms token verification
### Qualitative Metrics
- **Clarity**: Clear separation of concerns
- **Maintainability**: No auth code to maintain
- **Security**: Specialized providers
- **Flexibility**: User choice of providers
- **Simplicity**: Focus on core functionality
---
**Document Version**: 1.0
**Created**: 2025-11-24
**Author**: StarPunk Architecture Team
**Purpose**: Document simplified authentication architecture after IndieAuth server removal