Files
StarPunk/docs/decisions/ADR-016-indieauth-client-discovery.md
Phil Skentelbery 6a29b0199e Fix IndieAuth client discovery for production authentication
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>
2025-11-19 11:44:35 -07:00

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

  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":

{
  "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?

  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

<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:

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

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