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>
7.3 KiB
ADR-030: External Token Verification Architecture
Status
Accepted
Context
Following the decision in ADR-021 to use external IndieAuth providers, we need to define the architecture for token verification. Several critical questions arose during implementation planning:
- How should we handle the existing database migration that creates token tables?
- What caching strategy should we use for token verification?
- How should we handle network errors when contacting external providers?
- What are the security implications of caching tokens?
Decision
1. Database Migration Strategy
Keep migration 002 but document its future purpose.
The migration creates tokens and authorization_codes tables that are not used in V1 but will be needed if V2 adds an internal provider option. Rather than removing and later re-adding these tables, we keep them empty in V1.
Rationale:
- Empty tables have zero performance impact
- Avoids complex migration rollback/recreation cycles
- Provides clear upgrade path to V2
- Follows principle of forward compatibility
2. Token Caching Architecture
Implement a configurable memory cache with 5-minute default TTL.
class TokenCache:
"""Simple time-based token cache"""
def __init__(self, ttl=300, enabled=True):
self.ttl = ttl
self.enabled = enabled
self.cache = {} # token_hash -> (info, expiry)
Configuration:
MICROPUB_TOKEN_CACHE_ENABLED=true # Can disable for high security
MICROPUB_TOKEN_CACHE_TTL=300 # 5 minutes default
Security Measures:
- Store SHA256 hash of token, never plain text
- Memory-only storage (no persistence)
- Short TTL to limit revocation delay
- Option to disable entirely
3. Network Error Handling
Implement clear error messages with appropriate HTTP status codes.
| Scenario | HTTP Status | User Message |
|---|---|---|
| Auth server timeout | 503 | "Authorization server is unreachable" |
| Invalid token | 403 | "Access token is invalid or expired" |
| Network error | 503 | "Cannot connect to authorization server" |
| No token provided | 401 | "No access token provided" |
Implementation:
try:
response = httpx.get(endpoint, timeout=5.0)
except httpx.TimeoutError:
raise TokenEndpointError("Authorization server is unreachable")
4. Endpoint Discovery
Implement full IndieAuth spec discovery with fallbacks.
Priority order:
- HTTP Link header (highest priority)
- HTML link elements
- IndieAuth metadata endpoint
This ensures compatibility with all IndieAuth providers while following the specification exactly.
Rationale
Why Cache Tokens?
Performance:
- Reduces latency for Micropub posts (5ms vs 500ms)
- Reduces load on external authorization servers
- Improves user experience for rapid posting
Trade-offs Accepted:
- 5-minute revocation delay is acceptable for most use cases
- Can disable cache for high-security requirements
- Cache is memory-only, cleared on restart
Why Keep Empty Tables?
Simplicity:
- Simpler than conditional migrations
- Cleaner upgrade path to V2
- No production impact (tables unused)
- Avoids migration complexity
Forward Compatibility:
- V2 might add internal provider
- Tables already have correct schema
- Migration already tested and working
Why External-Only Verification?
Alignment with Principles:
- StarPunk is a Micropub server, not an auth server
- Users control their own identity infrastructure
- Reduces code complexity significantly
- Follows IndieWeb separation of concerns
Consequences
Positive
- Simplicity: No complex OAuth flows to implement
- Security: No tokens stored in database
- Performance: Cache provides fast token validation
- Flexibility: Users choose their auth providers
- Compliance: Full IndieAuth spec compliance
Negative
- Dependency: Requires external auth server availability
- Latency: Network call for uncached tokens (mitigated by cache)
- Revocation Delay: Up to 5 minutes for cached tokens (configurable)
Neutral
- Database: Unused tables in V1 (no impact, future-ready)
- Configuration: Requires ADMIN_ME setting (one-time setup)
- Documentation: Must explain external provider setup
Implementation Details
Token Verification Flow
1. Extract Bearer token from Authorization header
2. Check cache for valid cached result
3. If not cached:
a. Discover token endpoint from ADMIN_ME URL
b. Verify token with external endpoint
c. Cache result if valid
4. Validate response:
a. 'me' field matches ADMIN_ME
b. 'scope' includes 'create'
5. Return validation result
Security Checklist
- Never log tokens in plain text
- Use HTTPS for all token verification
- Implement timeout on HTTP requests
- Hash tokens before caching
- Validate SSL certificates
- Clear cache on configuration changes
Performance Targets
- Cached token verification: < 10ms
- Uncached token verification: < 500ms
- Endpoint discovery: < 1000ms (cached after first)
- Cache memory usage: < 10MB for 1000 tokens
Alternatives Considered
Alternative 1: No Token Cache
Pros: Immediate revocation, simpler code Cons: High latency (500ms per request), load on auth servers Verdict: Rejected - poor user experience
Alternative 2: Database Token Cache
Pros: Persistent cache, survives restarts Cons: Complex invalidation, security concerns Verdict: Rejected - unnecessary complexity
Alternative 3: Redis Token Cache
Pros: Distributed cache, proven solution Cons: Additional dependency, deployment complexity Verdict: Rejected - violates simplicity principle
Alternative 4: Remove Migration 002
Pros: Cleaner V1 codebase Cons: Complex V2 upgrade, breaks existing databases Verdict: Rejected - creates future problems
Migration Impact
For Existing Installations
- No database changes needed
- Add ADMIN_ME configuration
- Token verification switches to external
For New Installations
- Clean V1 implementation
- Empty future-use tables
- Simple configuration
Security Considerations
Token Revocation Delay
- Cached tokens remain valid for TTL duration
- Maximum exposure: 5 minutes default
- Can disable cache for immediate revocation
- Document delay in security guide
Network Security
- Always use HTTPS for token verification
- Validate SSL certificates
- Implement request timeouts
- Handle network errors gracefully
Cache Security
- SHA256 hash tokens before storage
- Memory-only cache (no disk persistence)
- Clear cache on shutdown
- Limit cache size to prevent DoS
References
- IndieAuth Spec Section 6.3 - Token verification
- OAuth 2.0 Bearer Token - Bearer token usage
- ADR-021 - Provider strategy decision
- ADR-029 - Integration strategy
Related Decisions
- ADR-021: IndieAuth Provider Strategy
- ADR-029: Micropub IndieAuth Integration Strategy
- ADR-005: IndieLogin Authentication
- ADR-010: Authentication Module Design
Document Version: 1.0 Created: 2024-11-24 Author: StarPunk Architecture Team Status: Accepted