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>
309 lines
9.7 KiB
Markdown
309 lines
9.7 KiB
Markdown
# ADR-016: IndieAuth Client Discovery Mechanism
|
|
|
|
## Status
|
|
|
|
**Superseded by ADR-019** - IndieLogin.com does not use h-app microformats for client discovery. PKCE implementation is the correct solution.
|
|
|
|
## Context
|
|
|
|
StarPunk uses IndieLogin.com as a delegated IndieAuth provider for admin authentication. During the first production deployment to https://starpunk.thesatelliteoflove.com, authentication failed with the error:
|
|
|
|
```
|
|
Request Error
|
|
There was a problem with the parameters of this request.
|
|
|
|
This client_id is not registered (https://starpunk.thesatelliteoflove.com)
|
|
```
|
|
|
|
### Root Cause
|
|
|
|
The IndieAuth specification requires authorization servers to verify client applications by fetching the `client_id` URL and discovering client metadata. StarPunk's implementation was missing this client discovery mechanism entirely.
|
|
|
|
### Why This Was Missed
|
|
|
|
1. Phase 3 authentication design focused on the authentication flow but didn't address client identification
|
|
2. Testing used DEV_MODE which bypasses IndieAuth entirely
|
|
3. The IndieAuth spec has evolved over time (2020 → 2022 → current) with different discovery mechanisms
|
|
4. Client discovery is a prerequisite that wasn't explicitly called out in our design
|
|
|
|
### IndieAuth Client Discovery Standards
|
|
|
|
The IndieAuth specification (as of 2025) supports three discovery mechanisms:
|
|
|
|
#### 1. OAuth Client ID Metadata Document (Current - 2022+)
|
|
|
|
A JSON document at `/.well-known/oauth-authorization-server` or linked via `rel="indieauth-metadata"`:
|
|
|
|
```json
|
|
{
|
|
"issuer": "https://example.com",
|
|
"client_id": "https://example.com",
|
|
"client_name": "App Name",
|
|
"client_uri": "https://example.com",
|
|
"redirect_uris": ["https://example.com/callback"]
|
|
}
|
|
```
|
|
|
|
**Pros**: Current standard, machine-readable, clean separation
|
|
**Cons**: Newer standard, may not be supported by older servers
|
|
|
|
#### 2. h-app Microformats (Legacy - Pre-2022)
|
|
|
|
HTML microformats markup in the page:
|
|
|
|
```html
|
|
<div class="h-app">
|
|
<a href="https://example.com" class="u-url p-name">App Name</a>
|
|
</div>
|
|
```
|
|
|
|
**Pros**: Widely supported, backward compatible, simple
|
|
**Cons**: Uses "legacy" standard, mixes presentation and metadata
|
|
|
|
#### 3. Basic HTTP 200 (Minimal)
|
|
|
|
Some servers accept any valid HTTP 200 response as sufficient client verification.
|
|
|
|
**Pros**: Simplest possible
|
|
**Cons**: Provides no metadata, not standards-compliant
|
|
|
|
## Decision
|
|
|
|
**Implement h-app microformats in base.html template**
|
|
|
|
We will add microformats2 h-app markup to the site footer for IndieAuth client discovery.
|
|
|
|
## Rationale
|
|
|
|
### Why h-app Microformats?
|
|
|
|
1. **Simplicity**: 3 lines of HTML vs new route with JSON endpoint
|
|
- Aligns with project philosophy: "Every line of code must justify its existence"
|
|
- Minimal implementation complexity
|
|
|
|
2. **Compatibility**: Works with all IndieAuth servers
|
|
- Supports legacy servers (IndieLogin.com likely runs older code)
|
|
- Backward compatible with 2020-era IndieAuth spec
|
|
- Forward compatible (current spec still supports h-app)
|
|
|
|
3. **Pragmatic**: Addresses immediate production need
|
|
- V1 requirement is "working IndieAuth authentication"
|
|
- h-app provides necessary client verification
|
|
- Low risk, high confidence in success
|
|
|
|
4. **Low Maintenance**: No new routes or endpoints
|
|
- Template-based, no server-side logic
|
|
- No additional testing surface
|
|
- Can't break existing functionality
|
|
|
|
5. **Standards-Compliant**: Still part of IndieAuth spec
|
|
- Officially supported for backward compatibility
|
|
- Used by many IndieAuth clients and servers
|
|
- Well-documented and understood
|
|
|
|
### Why Not OAuth Client ID Metadata Document?
|
|
|
|
While this is the "current" standard, we rejected it for V1 because:
|
|
|
|
1. **Complexity**: Requires new route, JSON serialization, additional tests
|
|
2. **Uncertainty**: Unknown if IndieLogin.com supports it (software may be older)
|
|
3. **Risk**: Higher chance of bugs in new endpoint
|
|
4. **V1 Scope**: Violates minimal viable product philosophy
|
|
|
|
This could be added in V2 for modern IndieAuth server support.
|
|
|
|
### Why Not Basic HTTP 200?
|
|
|
|
This provides no client metadata and isn't standards-compliant. While some servers may accept it, it doesn't fulfill the spirit of client verification and could fail with stricter authorization servers.
|
|
|
|
## Implementation
|
|
|
|
### Location
|
|
|
|
`templates/base.html` in the `<footer>` section
|
|
|
|
### Code
|
|
|
|
```html
|
|
<footer>
|
|
<p>StarPunk v{{ config.get('VERSION', '0.6.1') }}</p>
|
|
|
|
<!-- IndieAuth client discovery (h-app microformats) -->
|
|
<div class="h-app" hidden aria-hidden="true">
|
|
<a href="{{ config.SITE_URL }}" class="u-url p-name">{{ config.get('SITE_NAME', 'StarPunk') }}</a>
|
|
</div>
|
|
</footer>
|
|
```
|
|
|
|
### Attributes Explained
|
|
|
|
- `class="h-app"`: Microformats2 root class for application metadata
|
|
- `hidden`: HTML5 attribute to hide from visual display
|
|
- `aria-hidden="true"`: Hide from screen readers (not content, just metadata)
|
|
- `class="u-url p-name"`: Microformats2 properties for URL and name
|
|
- Uses Jinja2 config variables for dynamic values
|
|
|
|
## Consequences
|
|
|
|
### Positive
|
|
|
|
1. ✅ **Production Authentication Works**: Fixes critical blocker
|
|
2. ✅ **Standards Compliant**: Follows IndieAuth legacy standard
|
|
3. ✅ **Widely Compatible**: Works with old and new IndieAuth servers
|
|
4. ✅ **Simple to Maintain**: No server-side logic, just HTML
|
|
5. ✅ **Easy to Test**: Simple HTML assertion in tests
|
|
6. ✅ **Low Risk**: Minimal change, hard to break
|
|
7. ✅ **No Breaking Changes**: Purely additive
|
|
|
|
### Negative
|
|
|
|
1. ⚠️ **Uses Legacy Standard**: h-app is pre-2022 spec
|
|
- Mitigation: Still officially supported, widely used
|
|
2. ⚠️ **Mixes Concerns**: Metadata in presentation template
|
|
- Mitigation: Acceptable for V1, can refactor for V2
|
|
3. ⚠️ **Not Future-Proof**: May need modern JSON endpoint eventually
|
|
- Mitigation: Can add alongside h-app in future (hybrid approach)
|
|
|
|
### Neutral
|
|
|
|
1. **Information Disclosure**: Reveals site URL and name
|
|
- Already public in HTML title and page content
|
|
- No additional sensitive information exposed
|
|
|
|
2. **Performance**: Adds ~80 bytes to HTML
|
|
- Negligible impact on page load
|
|
- No server-side processing overhead
|
|
|
|
## Alternatives Considered
|
|
|
|
### Alternative 1: OAuth Client ID Metadata Document
|
|
|
|
**Implementation**: New route `GET /.well-known/oauth-authorization-server` returning JSON
|
|
|
|
**Rejected Because**:
|
|
- Higher complexity (new route, tests, JSON serialization)
|
|
- Unknown IndieLogin.com compatibility
|
|
- Violates V1 minimal scope
|
|
- Can add later if needed
|
|
|
|
### Alternative 2: Hybrid Approach (Both h-app and JSON)
|
|
|
|
**Implementation**: Both h-app markup AND JSON endpoint
|
|
|
|
**Rejected Because**:
|
|
- Unnecessary complexity for V1
|
|
- Duplication of data
|
|
- h-app alone is sufficient for current need
|
|
- Can upgrade to hybrid in V2 if required
|
|
|
|
### Alternative 3: Do Nothing (Rely on DEV_MODE)
|
|
|
|
**Rejected Because**:
|
|
- Production authentication completely broken
|
|
- Forces insecure development mode in production
|
|
- Violates security best practices
|
|
- Makes project undeployable
|
|
|
|
## Testing Strategy
|
|
|
|
### Unit Tests
|
|
|
|
Add to `tests/test_templates.py`:
|
|
|
|
```python
|
|
def test_h_app_microformats_present(client):
|
|
"""Verify h-app client discovery markup exists"""
|
|
response = client.get('/')
|
|
assert response.status_code == 200
|
|
assert b'class="h-app"' in response.data
|
|
|
|
def test_h_app_contains_site_url(client, app):
|
|
"""Verify h-app contains correct site URL"""
|
|
response = client.get('/')
|
|
assert app.config['SITE_URL'].encode() in response.data
|
|
```
|
|
|
|
### Integration Tests
|
|
|
|
1. Use microformats parser to verify h-app structure
|
|
2. Test with actual IndieLogin.com authentication
|
|
3. Verify no "client_id not registered" error
|
|
|
|
### Manual Testing
|
|
|
|
1. Deploy to production
|
|
2. Attempt admin login via IndieAuth
|
|
3. Verify authentication flow completes successfully
|
|
|
|
## Migration Path
|
|
|
|
No migration required:
|
|
- No database changes
|
|
- No configuration changes
|
|
- No breaking API changes
|
|
- Purely additive HTML change
|
|
|
|
Existing authenticated sessions remain valid.
|
|
|
|
## Future Considerations
|
|
|
|
### V2 Potential Enhancements
|
|
|
|
1. **Add JSON Metadata Endpoint**: Implement modern OAuth Client ID Metadata Document
|
|
2. **Hybrid Support**: Maintain h-app for compatibility while adding JSON
|
|
3. **Extended Metadata**: Add logo_uri, more detailed application info
|
|
4. **Dynamic Client Registration**: Support programmatic client registration
|
|
|
|
### Upgrade Path
|
|
|
|
When implementing V2 enhancements:
|
|
|
|
1. Keep h-app markup for backward compatibility
|
|
2. Add `/.well-known/oauth-authorization-server` endpoint
|
|
3. Add `<link rel="indieauth-metadata">` to HTML head
|
|
4. Document support for both legacy and modern discovery
|
|
|
|
This allows gradual migration without breaking existing integrations.
|
|
|
|
## Compliance
|
|
|
|
### IndieWeb Standards
|
|
|
|
- ✅ IndieAuth specification (legacy client discovery)
|
|
- ✅ Microformats2 h-app specification
|
|
- ✅ HTML5 standard (hidden attribute)
|
|
- ✅ ARIA accessibility standard
|
|
|
|
### Project Standards
|
|
|
|
- ✅ ADR-001: Minimal dependencies (no new packages)
|
|
- ✅ "Every line of code must justify its existence"
|
|
- ✅ Standards-first approach
|
|
- ✅ Progressive enhancement (server-side only)
|
|
|
|
## References
|
|
|
|
- [IndieAuth Specification](https://indieauth.spec.indieweb.org/)
|
|
- [Microformats2 h-app](https://microformats.org/wiki/h-app)
|
|
- [IndieLogin.com](https://indielogin.com/)
|
|
- [OAuth 2.0 Client ID Metadata Document](https://www.rfc-editor.org/rfc/rfc7591.html)
|
|
|
|
## Related Documents
|
|
|
|
- Phase 3: Authentication Design (`docs/design/phase-3-authentication.md`)
|
|
- ADR-005: IndieLogin Authentication (`docs/decisions/ADR-005-indielogin-authentication.md`)
|
|
- IndieAuth Client Discovery Analysis (`docs/reports/indieauth-client-discovery-analysis.md`)
|
|
|
|
## Version Impact
|
|
|
|
**Bug Classification**: Critical
|
|
**Version Increment**: v0.6.0 → v0.6.1 (patch release)
|
|
**Reason**: Critical bug fix for broken production authentication
|
|
|
|
---
|
|
|
|
**Decided**: 2025-11-19
|
|
**Author**: StarPunk Architect Agent
|
|
**Supersedes**: None
|
|
**Superseded By**: None (current)
|