Files
StarPunk/docs/decisions/ADR-030-external-token-verification-architecture.md
Phil Skentelbery a3bac86647 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>
2025-11-24 17:23:46 -07:00

251 lines
7.3 KiB
Markdown

# 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:
1. How should we handle the existing database migration that creates token tables?
2. What caching strategy should we use for token verification?
3. How should we handle network errors when contacting external providers?
4. 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.**
```python
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**:
```ini
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**:
```python
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:
1. HTTP Link header (highest priority)
2. HTML link elements
3. 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](https://www.w3.org/TR/indieauth/#token-verification) - Token verification
- [OAuth 2.0 Bearer Token](https://tools.ietf.org/html/rfc6750) - Bearer token usage
- [ADR-021](./ADR-021-indieauth-provider-strategy.md) - Provider strategy decision
- [ADR-029](./ADR-029-micropub-indieauth-integration.md) - 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