# IndieAuth Client Discovery Error - Architectural Analysis

**Date**: 2025-11-19
**Reviewer**: StarPunk Architect Agent
**Issue**: Production IndieAuth failure - "client_id is not registered"
**Severity**: CRITICAL - Blocks all production authentication
**Status**: Analysis complete, solution identified

---

## Executive Summary

**The proposed fix is INCORRECT and will not resolve the issue.**

The error "This client_id is not registered" occurs because IndieLogin.com cannot fetch and verify the `client_id` URL (https://starpunk.thesatelliteoflove.com). The proposed fix of adding `rel="authorization_endpoint"` and `rel="token_endpoint"` links to the HTML head is **backwards** - these links advertise where a **user's** identity provider endpoints are, not where a **client application's** endpoints are.

**Root Cause**: StarPunk is missing client identification metadata that IndieAuth servers need to verify the application.

**Correct Solution**: Implement one of three IndieAuth client discovery mechanisms (detailed below).

---

## Understanding IndieAuth Client Discovery

### The Authentication Flow

When a user tries to authenticate:

1. User submits their identity URL (me) to StarPunk
2. StarPunk redirects user to IndieLogin.com with:
   - `client_id=https://starpunk.thesatelliteoflove.com`
   - `redirect_uri=https://starpunk.thesatelliteoflove.com/auth/callback`
   - `state=<csrf-token>`
3. **IndieLogin.com fetches the client_id URL to verify the client**
4. IndieLogin.com authenticates the user
5. IndieLogin.com redirects back to StarPunk

The error occurs at **step 3** - IndieLogin.com cannot verify StarPunk as a legitimate client.

### What IndieAuth Servers Look For

Per the IndieAuth specification (2025 edition), authorization servers must verify clients by fetching the `client_id` URL and looking for one of these (in order of preference):

#### 1. Client ID Metadata Document (Current Standard - 2022+)

A JSON document at `/.well-known/oauth-authorization-server` or linked via `rel="indieauth-metadata"`:

```json
{
  "issuer": "https://starpunk.thesatelliteoflove.com",
  "client_id": "https://starpunk.thesatelliteoflove.com",
  "client_name": "StarPunk",
  "client_uri": "https://starpunk.thesatelliteoflove.com",
  "logo_uri": "https://starpunk.thesatelliteoflove.com/static/logo.png",
  "redirect_uris": [
    "https://starpunk.thesatelliteoflove.com/auth/callback"
  ]
}
```

#### 2. h-app Microformats (Legacy - Pre-2022)

HTML microformats markup in the client_id page:

```html
<div class="h-app">
  <a href="https://starpunk.thesatelliteoflove.com" class="u-url p-name">StarPunk</a>
  <img src="/static/logo.png" class="u-logo" alt="StarPunk">
  <p class="p-summary">A minimal IndieWeb CMS for publishing notes</p>
</div>
```

#### 3. Basic HTML (Minimal Fallback)

At minimum, the client_id URL must return a valid HTML page (some servers accept any 200 OK response).

---

## Analysis of Proposed Fix

### What Was Proposed

Add to `templates/base.html`:

```html
<link rel="authorization_endpoint" href="https://indielogin.com/auth">
<link rel="token_endpoint" href="https://indielogin.com/token">
```

### Why This Is Wrong

These `rel` values serve a **completely different purpose**:

1. **authorization_endpoint** and **token_endpoint** advertise where a **user's identity provider** has its endpoints
2. They would be used on a **user's personal website** (their `me` URL), not on a **client application**
3. They tell IndieAuth clients "here's where to authenticate ME", not "here's information about THIS application"

**Example of correct usage**: If Alice's personal site is `https://alice.example.com`, HER website would include:

```html
<link rel="authorization_endpoint" href="https://alice.example.com/auth">
<link rel="token_endpoint" href="https://alice.example.com/token">
```

This tells IndieAuth clients "to authenticate Alice, use these endpoints."

StarPunk is a **client application**, not an identity provider, so these links are inappropriate and won't solve the registration error.

### Why It Appeared to Work (If It Did)

If adding these links appeared to resolve the issue, it's likely coincidental:

1. The HTTP request to the client_id URL succeeded (returned 200 OK)
2. IndieLogin.com accepted the basic HTML response
3. The specific `rel` values were ignored

This would be a fragile solution that doesn't follow standards.

---

## Correct Solutions

### Recommendation: Solution 2 (h-app Microformats)

I recommend implementing h-app microformats for backward compatibility and simplicity.

### Solution 1: Client ID Metadata Document (Most Standards-Compliant)

**Complexity**: Medium
**Standards**: Current (2022+)
**Compatibility**: Modern IndieAuth servers only

#### Implementation

1. Create endpoint: `GET /.well-known/oauth-authorization-server`
2. Return JSON metadata document
3. Set `Content-Type: application/json`

**Code Location**: `starpunk/routes/public.py`

```python
@public_bp.route('/.well-known/oauth-authorization-server')
def client_metadata():
    """OAuth Client ID Metadata Document for IndieAuth"""
    metadata = {
        "issuer": current_app.config['SITE_URL'],
        "client_id": current_app.config['SITE_URL'],
        "client_name": current_app.config.get('SITE_NAME', 'StarPunk'),
        "client_uri": current_app.config['SITE_URL'],
        "redirect_uris": [
            f"{current_app.config['SITE_URL']}/auth/callback"
        ]
    }
    return jsonify(metadata)
```

**Pros**:
- Current standard (2022+)
- Clean separation of concerns
- Machine-readable
- Easy to extend

**Cons**:
- Not supported by older IndieAuth servers
- Requires new route
- May not be supported by IndieLogin.com if it's running older code

---

### Solution 2: h-app Microformats (Recommended)

**Complexity**: Low
**Standards**: Legacy (pre-2022) but widely supported
**Compatibility**: All IndieAuth servers

#### Implementation

Add to `templates/base.html` in the `<body>` (or create a dedicated footer/header):

```html
<div class="h-app" style="display: none;">
  <a href="{{ config.SITE_URL }}" class="u-url p-name">{{ config.SITE_NAME }}</a>
  <p class="p-summary">A minimal IndieWeb CMS for publishing notes</p>
</div>
```

**Minimal version** (if we want to keep it even simpler):

```html
<div class="h-app" hidden>
  <a href="{{ config.SITE_URL }}" class="u-url p-name">StarPunk</a>
</div>
```

**Where to add**: In `base.html`, inside `<body>` tag, preferably in the footer area.

**Pros**:
- Widely supported (backward compatible)
- Simple to implement (3 lines of HTML)
- No new routes needed
- Likely what IndieLogin.com expects
- Can be hidden from users (display: none or hidden attribute)

**Cons**:
- Uses "legacy" standard (though still widely supported)
- Mixes presentation and authentication metadata

---

### Solution 3: Hybrid Approach (Most Robust)

Implement **both** solutions for maximum compatibility:

1. Add h-app microformats to base.html (for legacy support)
2. Add /.well-known/oauth-authorization-server endpoint (for modern support)

**Pros**:
- Works with all IndieAuth servers
- Future-proof
- Standards-compliant

**Cons**:
- Slight duplication of information
- More implementation work

---

## Testing the Fix

### Verification Steps

1. **Test client_id fetch**:
   ```bash
   curl -I https://starpunk.thesatelliteoflove.com
   ```
   Should return 200 OK

2. **Verify h-app markup** (if using Solution 2):
   ```bash
   curl https://starpunk.thesatelliteoflove.com | grep h-app
   ```
   Should show the h-app div

3. **Test with IndieAuth validator**:
   Use https://www.w3.org/TR/indieauth/validator or a similar tool

4. **Test actual auth flow**:
   - Navigate to /admin/login
   - Enter your identity URL
   - Verify IndieLogin.com accepts the client_id
   - Complete authentication

### Expected Results After Fix

- IndieLogin.com should no longer show "client_id is not registered"
- User should see authentication prompt for their identity
- Successful auth should redirect back to StarPunk

---

## Architecture Decision Record

This issue reveals a **gap in our Phase 3 implementation** - we implemented IndieAuth **authentication** but not IndieAuth **client identification**.

### Should We Create an ADR?

**Yes** - This is an architectural decision about how StarPunk identifies itself to authorization servers.

**ADR Subject**: Client identification mechanism for IndieAuth

**Decision Points**:
1. Which client discovery mechanism to implement
2. Whether to support legacy h-app or modern JSON metadata
3. Where to place the metadata (route vs template)

### Recommended ADR Outcome

**Decision**: Implement h-app microformats in base.html (Solution 2)

**Rationale**:
1. **Simplicity**: Aligns with project philosophy ("minimal code")
2. **Compatibility**: Works with all IndieAuth servers including older ones
3. **Pragmatic**: IndieLogin.com likely expects h-app (it's older software)
4. **Low Risk**: 3 lines of HTML vs new route with JSON endpoint
5. **V1 Scope**: Minimal viable solution for single-user system

**Future Considerations**:
- V2 could add JSON metadata endpoint for standards compliance
- Hybrid approach if we encounter compatibility issues

---

## Version Impact Analysis

### Is This a Bug or Missing Feature?

**Classification**: Bug (Critical)

**Reasoning**:
- Phase 3/4 claimed to implement "IndieAuth authentication"
- Production authentication is completely broken
- Feature was tested only in DEV_MODE (bypasses IndieAuth)
- This is a missing requirement from the IndieAuth spec

### Version Number Impact

**Current Version**: v0.6.0 (released 2025-11-19)

**Recommended Version After Fix**: v0.6.1

**Rationale** (per ADR-008 Versioning Strategy):
- **Not v0.7.0**: This is a bug fix, not a new feature
- **Not v1.0.0**: Not a breaking change to API or data format
- **v0.6.1**: Patch release for critical bug fix

**Severity Level**: CRITICAL
- Production authentication completely broken
- No workaround except switching to DEV_MODE (insecure)
- Affects all production deployments

---

## Git Strategy

### Branch Strategy (per ADR-009)

**Recommended Approach**: Hotfix branch

```bash
git checkout -b hotfix/indieauth-client-discovery
```

**Rationale**:
- Critical production bug
- Needs immediate fix
- Should be merged directly to main
- Should be tagged as v0.6.1

**Not a Feature Branch** because:
- This isn't new functionality
- It's fixing broken production behavior
- Hotfix process is appropriate

### Commit Strategy

**Single Commit** vs **Multiple Commits**:

Recommend **single atomic commit**:
- Change is small (adding h-app markup)
- Logically cohesive
- Easy to cherry-pick or revert if needed

**Commit Message Template**:

```
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.

Fixes critical bug preventing production authentication.

Related: Phase 3 Authentication implementation
```

---

## Documentation Updates Required

### Files to Update

1. **CHANGELOG.md**:
   - Add v0.6.1 section
   - Document bug fix under "Fixed"
   - Reference IndieAuth client discovery

2. **docs/decisions/ADR-016-indieauth-client-discovery.md** (NEW):
   - Document decision to use h-app microformats
   - Explain alternatives considered
   - Document why this was missed in Phase 3

3. **docs/design/phase-3-authentication.md** (UPDATE):
   - Add section on client discovery requirements
   - Document h-app implementation
   - Note this as errata/addition to original spec

4. **docs/reports/indieauth-client-discovery-fix.md** (NEW):
   - Implementation report
   - Testing results
   - Deployment notes

---

## Acceptance Criteria for Fix

The fix is complete when:

- [ ] h-app microformats added to base.html (or JSON endpoint implemented)
- [ ] StarPunk homepage returns 200 OK and contains client identification
- [ ] IndieLogin.com accepts client_id without "not registered" error
- [ ] Full authentication flow works in production
- [ ] Tests added to verify h-app markup presence
- [ ] ADR-016 created documenting decision
- [ ] CHANGELOG.md updated for v0.6.1
- [ ] Version bumped to v0.6.1 in starpunk/__init__.py
- [ ] Hotfix branch merged to main
- [ ] Release tagged as v0.6.1
- [ ] Production deployment tested and verified

---

## Implementation Specification

### Recommended Implementation (h-app microformats)

**File**: `templates/base.html`

**Location**: Add in `<footer>` section, before closing `</footer>` tag

**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>
```

**Justification for Location**:
- Footer is semantically appropriate for metadata
- `hidden` attribute hides from visual presentation
- `aria-hidden="true"` hides from screen readers
- Still parseable by IndieAuth servers
- Doesn't affect page layout

**CSS Not Required**: The `hidden` attribute provides sufficient hiding.

---

## Risk Assessment

### Risks of Current State (No Fix)

- **CRITICAL**: Production authentication completely broken
- Users cannot access admin interface in production
- Forces use of DEV_MODE (security risk)
- Project cannot be deployed to production

### Risks of Proposed Fix (h-app microformats)

- **LOW**: Minimal risk
- Small, localized change
- Widely supported standard
- Easy to revert if issues occur
- No database migrations
- No breaking changes

### Risks of Alternative Fix (JSON metadata endpoint)

- **MEDIUM**: Moderate risk
- New route could have bugs
- May not be supported by IndieLogin.com
- More code to test
- Higher chance of unintended side effects

---

## Performance Impact

### h-app Microformats (Recommended)

**Impact**: Negligible

- Adds ~80 bytes to HTML response
- No additional HTTP requests
- No database queries
- No server-side processing
- Minimal parsing overhead for IndieAuth servers

**Performance Score**: No measurable impact

### JSON Metadata Endpoint

**Impact**: Minimal

- One additional route
- Negligible JSON serialization overhead
- Only called during auth flow (infrequent)
- No database queries

**Performance Score**: Negligible impact

---

## Security Considerations

### Security Impact of h-app Microformats

**Positive**:
- Enables proper IndieAuth client verification
- Prevents client impersonation

**Neutral**:
- Exposes client metadata (already public via HTTP)
- No sensitive information disclosed

**No Security Risks Identified**

### Information Disclosure

The h-app markup reveals:
- Site URL (already public)
- Site name (already public in page title)

**Assessment**: No additional information disclosure beyond what's already in public HTML.

---

## Standards Compliance Checklist

### IndieWeb Standards

- [ ] Implements IndieAuth client discovery (currently missing)
- [ ] Uses h-app microformats OR Client ID Metadata Document
- [ ] Client metadata accessible via HTTP GET
- [ ] Client_id URL returns 200 OK

### Web Standards

- [x] Valid HTML5 (hidden attribute is standard)
- [x] Valid microformats2 (h-app, u-url, p-name)
- [x] Accessible (aria-hidden for screen readers)
- [x] SEO neutral (hidden content not indexed)

---

## Testing Strategy

### Unit Tests

**File**: `tests/test_templates.py` (new file or existing)

**Test Cases**:
1. Test h-app markup present in base.html
2. Test h-app contains correct URL
3. Test h-app contains site name
4. Test h-app is hidden from visual display

```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
    assert b'class="u-url p-name"' 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

**Manual Testing**:
1. Deploy to production
2. Attempt IndieAuth login
3. Verify no "client_id not registered" error
4. Complete authentication flow
5. Access admin dashboard

**Automated Testing**:
- Use IndieAuth validator tool
- Verify microformats parsing

---

## Deployment Considerations

### Deployment Process

1. **Build**: No build changes required
2. **Database**: No migrations required
3. **Configuration**: No config changes required
4. **Rollback**: Simple (revert commit)

### Rollout Strategy

**Recommended**: Direct deployment (low risk)

1. Merge hotfix branch to main
2. Tag as v0.6.1
3. Deploy to production
4. Verify authentication works
5. Monitor for issues

**No Gradual Rollout Needed**:
- Change is low risk
- No breaking changes
- Easy to revert

### Container Impact

**Container Build**:
- No Containerfile changes needed
- Rebuild image to include template update
- Same base image and dependencies

**Container Tag**: Update to v0.6.1

---

## Lessons Learned

### What Went Wrong

1. **Incomplete Specification**: Phase 3 design didn't include client discovery requirements
2. **Testing Gap**: Only tested with DEV_MODE (bypasses IndieAuth)
3. **Spec Understanding**: Missed IndieAuth client identification requirement
4. **Documentation**: IndieAuth spec has multiple versions (2020, 2022) with different requirements

### Process Improvements

1. **Testing Requirements**: Always test production authentication paths
2. **Spec Review**: Review full IndieAuth specification, not just authentication flow
3. **Integration Testing**: Test with actual IndieLogin.com, not just mocks
4. **Documentation**: Cross-reference all IndieWeb specs (IndieAuth, Micropub, Webmention)

### Future Prevention

1. Create comprehensive IndieAuth compliance checklist
2. Add integration tests with actual authorization servers
3. Review all IndieWeb specs for hidden requirements
4. Test in production-like environment (not just DEV_MODE)

---

## Conclusion

**Proposed Fix Assessment**: ❌ INCORRECT

**Correct Fix**: Add h-app microformats to base.html

**Severity**: CRITICAL (blocks production authentication)

**Recommended Action**: Implement Solution 2 (h-app microformats) immediately

**Version**: Bump to v0.6.1 (patch release)

**Branch Strategy**: Use hotfix branch per ADR-009

**Documentation**: Create ADR-016, update CHANGELOG.md

**Risk Level**: LOW (simple, well-understood fix)

**Timeline**: Can be implemented in < 1 hour

---

## Next Steps for Developer

1. Create hotfix branch: `hotfix/indieauth-client-discovery`
2. Add h-app microformats to `templates/base.html`
3. Update version to v0.6.1 in `starpunk/__init__.py`
4. Add tests for h-app markup presence
5. Create ADR-016 documenting decision
6. Update CHANGELOG.md with v0.6.1 entry
7. Create implementation report
8. Test authentication flow in production
9. Commit with message template above
10. Merge to main and tag v0.6.1

---

**Analysis by**: StarPunk Architect Agent
**Date**: 2025-11-19
**Document Version**: 1.0
**Status**: Ready for implementation
