Add h-app microformats markup to base.html to enable IndieLogin.com to verify StarPunk as a legitimate OAuth client. Without this markup, IndieLogin returns "client_id is not registered" error, blocking all production authentication. The h-app markup provides client identification per IndieAuth legacy standard, which is widely supported by authorization servers including IndieLogin.com. Changes: - Add h-app microformats div to base.html footer (hidden) - Update version to v0.6.1 (patch release per ADR-008) - Update CHANGELOG.md with v0.6.1 release notes - Add 6 comprehensive tests for h-app markup (all passing) - Create ADR-016 documenting client discovery decision - Create architecture analysis report - Create implementation report Tests: 456 total, 455 passing (99.78%) New tests: 6 for h-app microformats (100% passing) Fixes critical bug preventing production authentication. Related: Phase 3 Authentication implementation, ADR-016 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude <noreply@anthropic.com>
9.6 KiB
ADR-016: IndieAuth Client Discovery Mechanism
Status
Accepted
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
- Phase 3 authentication design focused on the authentication flow but didn't address client identification
- Testing used DEV_MODE which bypasses IndieAuth entirely
- The IndieAuth spec has evolved over time (2020 → 2022 → current) with different discovery mechanisms
- 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":
{
"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:
<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?
-
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
-
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)
-
Pragmatic: Addresses immediate production need
- V1 requirement is "working IndieAuth authentication"
- h-app provides necessary client verification
- Low risk, high confidence in success
-
Low Maintenance: No new routes or endpoints
- Template-based, no server-side logic
- No additional testing surface
- Can't break existing functionality
-
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:
- Complexity: Requires new route, JSON serialization, additional tests
- Uncertainty: Unknown if IndieLogin.com supports it (software may be older)
- Risk: Higher chance of bugs in new endpoint
- 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
<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 metadatahidden: HTML5 attribute to hide from visual displayaria-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
- ✅ Production Authentication Works: Fixes critical blocker
- ✅ Standards Compliant: Follows IndieAuth legacy standard
- ✅ Widely Compatible: Works with old and new IndieAuth servers
- ✅ Simple to Maintain: No server-side logic, just HTML
- ✅ Easy to Test: Simple HTML assertion in tests
- ✅ Low Risk: Minimal change, hard to break
- ✅ No Breaking Changes: Purely additive
Negative
- ⚠️ Uses Legacy Standard: h-app is pre-2022 spec
- Mitigation: Still officially supported, widely used
- ⚠️ Mixes Concerns: Metadata in presentation template
- Mitigation: Acceptable for V1, can refactor for V2
- ⚠️ Not Future-Proof: May need modern JSON endpoint eventually
- Mitigation: Can add alongside h-app in future (hybrid approach)
Neutral
-
Information Disclosure: Reveals site URL and name
- Already public in HTML title and page content
- No additional sensitive information exposed
-
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:
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
- Use microformats parser to verify h-app structure
- Test with actual IndieLogin.com authentication
- Verify no "client_id not registered" error
Manual Testing
- Deploy to production
- Attempt admin login via IndieAuth
- 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
- Add JSON Metadata Endpoint: Implement modern OAuth Client ID Metadata Document
- Hybrid Support: Maintain h-app for compatibility while adding JSON
- Extended Metadata: Add logo_uri, more detailed application info
- Dynamic Client Registration: Support programmatic client registration
Upgrade Path
When implementing V2 enhancements:
- Keep h-app markup for backward compatibility
- Add
/.well-known/oauth-authorization-serverendpoint - Add
<link rel="indieauth-metadata">to HTML head - 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
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)