Files
StarPunk/docs/decisions/ADR-019-indieauth-pkce-authentication.md
Phil Skentelbery 5e50330bdf feat: Implement PKCE authentication for IndieLogin.com
This fixes critical IndieAuth authentication by implementing PKCE (Proof Key
for Code Exchange) as required by IndieLogin.com API specification.

Added:
- PKCE code_verifier and code_challenge generation (RFC 7636)
- Database column: auth_state.code_verifier for PKCE support
- Issuer validation for authentication callbacks
- Comprehensive PKCE unit tests (6 tests, all passing)
- Database migration script for code_verifier column

Changed:
- Corrected IndieLogin.com API endpoints (/authorize and /token)
- State token validation now returns code_verifier for token exchange
- Authentication flow follows IndieLogin.com API specification exactly
- Enhanced logging with code_verifier redaction

Removed:
- OAuth metadata endpoint (/.well-known/oauth-authorization-server)
  Added in v0.7.0 but not required by IndieLogin.com
- h-app microformats markup from templates
  Modified in v0.7.1 but not used by IndieLogin.com
- indieauth-metadata link from HTML head

Security:
- PKCE prevents authorization code interception attacks
- Issuer validation prevents token substitution attacks
- Code verifier securely stored, redacted in logs, and single-use

Documentation:
- Version: 0.8.0
- CHANGELOG updated with v0.8.0 entry and v0.7.x notes
- ADR-016 and ADR-017 marked as superseded by ADR-019
- Implementation report created in docs/reports/
- Test update guide created in TODO_TEST_UPDATES.md

Breaking Changes:
- Users mid-authentication will need to restart login after upgrade
- Database migration required before deployment

Related: ADR-019

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

Co-Authored-By: Claude <noreply@anthropic.com>
2025-11-19 15:43:38 -07:00

227 lines
9.7 KiB
Markdown

# 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)