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

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:

  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.

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:

  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

  • 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