# ADR-019: IndieAuth Correct Implementation Based on IndieLogin.com API ## Status Accepted ## Context StarPunk's IndieAuth authentication has been failing in production despite implementing various fixes (ADR-016, ADR-017) including OAuth metadata endpoints and h-app microformats. These implementations were based on misunderstanding the requirements of the specific service we use: IndieLogin.com. ### The Core Problem We conflated two different things: 1. **Generic IndieAuth specification** - Full OAuth 2.0 with client discovery mechanisms 2. **IndieLogin.com API** - Simplified authentication-only service with specific requirements IndieLogin.com is a **simplified authentication service**, not a full OAuth 2.0 authorization server. It has specific API requirements that differ from the generic IndieAuth specification. ### What We Misunderstood 1. **Authentication vs Authorization**: IndieLogin.com provides **authentication** (who are you?) not **authorization** (what can you access?). No scopes, no access tokens for API access - just identity verification. 2. **Client Discovery Not Required**: IndieLogin.com accepts any valid `client_id` URL without pre-registration or metadata endpoints. The OAuth metadata endpoint and h-app microformats we added are unnecessary. 3. **PKCE is Mandatory**: IndieLogin.com **requires** PKCE (Proof Key for Code Exchange) parameters for security. Our current implementation lacks this entirely. 4. **Wrong Endpoints**: We're using `/auth` when we should use `/authorize` and `/token`. ### Critical Missing Pieces Our current implementation in `starpunk/auth.py` is missing: - PKCE `code_verifier` generation and storage - PKCE `code_challenge` generation and transmission - `code_verifier` in token exchange - Issuer (`iss`) validation - Correct API endpoints ### Why Previous Fixes Failed - **ADR-016 (h-app microformats)**: Added client discovery mechanism that IndieLogin.com doesn't use - **ADR-017 (OAuth metadata endpoint)**: Added OAuth endpoint that IndieLogin.com doesn't check - **Original implementation**: Missing PKCE, wrong endpoints, incomplete parameter set ## Decision **Implement IndieAuth authentication following the IndieLogin.com API specification exactly**, specifically: 1. **Implement PKCE Flow** - Generate cryptographically secure `code_verifier` (43-character random string) - Generate `code_challenge` (SHA256 hash of verifier, base64-url encoded) - Store `code_verifier` with state token in database - Send `code_challenge` and `code_challenge_method=S256` in authorization request - Send `code_verifier` in token exchange request 2. **Use Correct IndieLogin.com Endpoints** - Authorization: `https://indielogin.com/authorize` (not `/auth`) - Token exchange: `https://indielogin.com/token` (not `/auth`) 3. **Required Parameters for Authorization Request** - `client_id` - Our application URL - `redirect_uri` - Our callback URL (must be on same domain) - `state` - Random CSRF protection token - `code_challenge` - PKCE challenge - `code_challenge_method` - Must be `S256` - `me` - User's URL (optional, prompts if omitted) 4. **Required Parameters for Token Exchange** - `code` - Authorization code from callback - `client_id` - Our application URL (same as authorization) - `redirect_uri` - Our callback URL (same as authorization) - `code_verifier` - Original PKCE verifier 5. **Validate Callback Parameters** - Verify `state` matches stored value (CSRF protection) - Verify `iss` equals `https://indielogin.com/` (issuer validation) - Extract `code` for token exchange 6. **Remove Unnecessary Components** - Remove OAuth metadata endpoint (`/.well-known/oauth-authorization-server`) - Remove h-app microformats markup from templates - Remove `indieauth-metadata` link from HTML head - Remove unused `response_type` parameter from authorization request ## Rationale ### Why This Approach is Correct 1. **Based on Official Documentation**: Every decision comes directly from https://indielogin.com/api, the authoritative source for the service we use. 2. **PKCE is Non-Negotiable**: IndieLogin.com requires it for security. PKCE prevents authorization code interception attacks, especially important for public clients. 3. **Simple Authentication Flow**: We need identity verification (web sign-in), not resource authorization. IndieLogin.com provides exactly this. 4. **No Client Registration Required**: IndieLogin.com accepts any valid `client_id` URL. Pre-registration mechanisms add complexity without benefit. 5. **Security Best Practices**: - State token prevents CSRF attacks - PKCE prevents authorization code interception - Issuer validation prevents token substitution - Single-use tokens prevent replay attacks ### Alignment with Project Principles 1. **Minimal Code**: Removes ~73 lines of unnecessary code (metadata endpoint, microformats) 2. **Standards First**: Follows official IndieLogin.com API specification 3. **"Every line must justify existence"**: Eliminates features that don't serve actual requirements 4. **No Lock-in**: Standard OAuth/PKCE implementation portable to other services ## Consequences ### Positive 1. **Authentication Will Work**: Follows IndieLogin.com API requirements exactly 2. **Simpler Codebase**: Net reduction of ~23 lines after adding PKCE and removing unnecessary features 3. **Better Security**: PKCE protection against authorization code attacks 4. **Standards Compliant**: Proper PKCE implementation per RFC 7636 5. **More Maintainable**: Clearer code with focused purpose 6. **Better Testability**: Well-defined flow with clear inputs/outputs ### Negative 1. **Database Migration Required**: Must add `code_verifier` column to `auth_state` table - Mitigation: Simple `ALTER TABLE`, backward compatible with default value 2. **Breaking Change for In-Flight Logins**: Users mid-authentication must restart - Mitigation: State tokens expire in 5 minutes anyway, minimal impact - Existing sessions remain valid (no logout of authenticated users) 3. **More Complex Auth Flow**: PKCE adds generation/storage/validation steps - Mitigation: Security benefit justifies complexity - Well-encapsulated in helper functions ### Neutral 1. **Code Changes**: Adds ~50 lines for PKCE, removes ~73 lines of unnecessary features (net -23 lines) 2. **Testing**: More test cases for PKCE, but clearer test boundaries ## Superseded Decisions This ADR supersedes: 1. **ADR-016: IndieAuth Client Discovery Mechanism** - h-app microformats not required by IndieLogin.com - Status: Superseded 2. **ADR-017: OAuth Client ID Metadata Document Implementation** - OAuth metadata endpoint not required by IndieLogin.com - Status: Superseded This ADR corrects the implementation details (but not the concept) in: 3. **ADR-005: IndieLogin Authentication Integration** - Authentication flow concept remains valid - Implementation corrected: added PKCE, corrected endpoints, added issuer validation - Status: Accepted (with implementation note) ## Version Impact **Change Type**: Critical bug fix (authentication completely broken in production) **Semantic Versioning Analysis**: - **Fixes broken feature**: IndieAuth authentication - **Removes features**: OAuth metadata endpoint (added in v0.7.0, never functioned) - **Adds security enhancement**: PKCE implementation - **Database schema change**: Adding column (backward compatible with default) **Version Decision**: See versioning guidance document for final determination based on current release state. ## Compliance ### IndieLogin.com API Requirements - Uses `/authorize` endpoint for authentication initiation - Uses `/token` endpoint for code exchange - Sends all required parameters per API documentation - Implements required PKCE flow - Validates state and issuer per security recommendations ### PKCE Specification (RFC 7636) - code_verifier: 43-128 character URL-safe random string - code_challenge: Base64-URL encoded SHA256 hash - code_challenge_method: S256 - Proper storage and single-use validation ### Project Standards - Minimal code principle - Standards-first approach - Security best practices - Clear documentation of decisions ## Implementation Notes The technical implementation is documented in: - **Design Document**: `/home/phil/Projects/starpunk/docs/designs/indieauth-pkce-authentication.md` - Technical specifications, flow diagrams, PKCE implementation details - **Implementation Guide**: Included in design document - Step-by-step developer instructions, code changes, testing strategy ## References ### Primary Source - **IndieLogin.com API Documentation**: https://indielogin.com/api - Authoritative source for all implementation decisions ### Supporting Specifications - **PKCE Specification (RFC 7636)**: https://www.rfc-editor.org/rfc/rfc7636 - **OAuth 2.0 (RFC 6749)**: https://www.rfc-editor.org/rfc/rfc6749 - **IndieAuth Specification**: https://indieauth.spec.indieweb.org/ (context only) ### Internal Documentation - ADR-005: IndieLogin Authentication Integration (conceptual flow) - ADR-010: Authentication Module Design - ADR-016: IndieAuth Client Discovery Mechanism (superseded) - ADR-017: OAuth Client ID Metadata Document (superseded) ## What We Learned 1. **Read the specific API documentation first**, not generic specifications 2. **Service-specific implementations matter**: IndieLogin.com is not a generic IndieAuth server 3. **PKCE is increasingly required**: Modern OAuth services mandate it for public clients 4. **Authentication ≠ Authorization**: Different use cases require different OAuth flows 5. **Simpler is often correct**: Unnecessary features indicate misunderstanding of requirements --- **Decided**: 2025-11-19 **Author**: StarPunk Architect **Supersedes**: ADR-016, ADR-017 **Corrects**: ADR-005 (implementation details)