# IndieAuth Implementation Questions - Answered

## Quick Reference

All architectural questions have been answered. This document provides the concrete guidance needed for implementation.

## Questions & Answers

### ✅ Q1: External Token Endpoint Response Format

**Answer**: Follow the IndieAuth spec exactly (W3C TR).

**Expected Response**:
```json
{
  "me": "https://user.example.net/",
  "client_id": "https://app.example.com/",
  "scope": "create update delete"
}
```

**Error Responses**: HTTP 400, 401, or 403 for invalid tokens.

---

### ✅ Q2: HTML Discovery Headers

**Answer**: These are links users add to THEIR websites, not StarPunk.

**User's HTML** (on their personal domain):
```html
<link rel="authorization_endpoint" href="https://indielogin.com/auth">
<link rel="token_endpoint" href="https://tokens.indieauth.com/token">
<link rel="micropub" href="https://your-starpunk.example.com/api/micropub">
```

**StarPunk's Role**: Discover these endpoints from the user's URL, don't generate them.

---

### ✅ Q3: Migration Strategy

**Architectural Decision**: Keep migration 002, document it as future-use.

**Action Items**:
1. Keep the migration file as-is
2. Add comment: "Tables created for future V2 internal provider support"
3. Don't use these tables in V1 (external verification only)
4. No impact on existing production databases

**Rationale**: Empty tables cause no harm, avoid migration complexity later.

---

### ✅ Q4: Error Handling

**Answer**: Show clear, informative error messages.

**Error Messages**:
- **Auth server down**: "Authorization server is unreachable. Please try again later."
- **Invalid token**: "Access token is invalid or expired. Please re-authorize."
- **Network error**: "Cannot connect to authorization server."

**HTTP Status Codes**:
- 401: No token provided
- 403: Invalid/expired token
- 503: Auth server unreachable

---

### ✅ Q5: Cache Revocation Delay

**Architectural Decision**: Use 5-minute cache with configuration options.

**Implementation**:
```python
# Default: 5-minute cache
MICROPUB_TOKEN_CACHE_TTL=300
MICROPUB_TOKEN_CACHE_ENABLED=true

# High security: disable cache
MICROPUB_TOKEN_CACHE_ENABLED=false
```

**Security Notes**:
- SHA256 hash tokens before caching
- Memory-only cache (not persisted)
- Document 5-minute delay in security guide
- Allow disabling for high-security needs

---

## Implementation Checklist

### Immediate Actions

1. **Remove Internal Provider Code**:
   - Delete `/auth/authorize` endpoint
   - Delete `/auth/token` endpoint
   - Remove token issuance logic
   - Remove authorization code generation

2. **Implement External Verification**:
   ```python
   # Core verification function
   def verify_micropub_token(bearer_token, expected_me):
       # 1. Check cache (if enabled)
       # 2. Discover token endpoint from expected_me
       # 3. Verify with external endpoint
       # 4. Cache result (if enabled)
       # 5. Return validation result
   ```

3. **Add Configuration**:
   ```ini
   # Required
   ADMIN_ME=https://user.example.com

   # Optional (with defaults)
   MICROPUB_TOKEN_CACHE_ENABLED=true
   MICROPUB_TOKEN_CACHE_TTL=300
   ```

4. **Update Error Handling**:
   ```python
   try:
       response = httpx.get(endpoint, timeout=5.0)
   except httpx.TimeoutError:
       return error(503, "Authorization server is unreachable")
   ```

---

## Code Examples

### Token Verification
```python
def verify_token(bearer_token: str, token_endpoint: str, expected_me: str) -> Optional[dict]:
    """Verify token with external endpoint"""
    try:
        response = httpx.get(
            token_endpoint,
            headers={'Authorization': f'Bearer {bearer_token}'},
            timeout=5.0
        )

        if response.status_code == 200:
            data = response.json()
            if data.get('me') == expected_me and 'create' in data.get('scope', ''):
                return data
        return None

    except httpx.TimeoutError:
        raise TokenEndpointError("Authorization server is unreachable")
```

### Endpoint Discovery
```python
def discover_token_endpoint(me_url: str) -> str:
    """Discover token endpoint from user's URL"""
    response = httpx.get(me_url)

    # 1. Check HTTP Link header
    if link := parse_link_header(response.headers.get('Link'), 'token_endpoint'):
        return urljoin(me_url, link)

    # 2. Check HTML <link> tags
    if 'text/html' in response.headers.get('content-type', ''):
        if link := parse_html_link(response.text, 'token_endpoint'):
            return urljoin(me_url, link)

    raise DiscoveryError(f"No token endpoint found at {me_url}")
```

### Micropub Endpoint
```python
@app.route('/api/micropub', methods=['POST'])
def micropub_endpoint():
    # Extract token
    auth = request.headers.get('Authorization', '')
    if not auth.startswith('Bearer '):
        return {'error': 'unauthorized'}, 401

    token = auth[7:]  # Remove "Bearer "

    # Verify token
    try:
        token_info = verify_micropub_token(token, app.config['ADMIN_ME'])
        if not token_info:
            return {'error': 'forbidden'}, 403
    except TokenEndpointError as e:
        return {'error': 'temporarily_unavailable', 'error_description': str(e)}, 503

    # Process Micropub request
    # ... create note ...

    return '', 201, {'Location': note_url}
```

---

## Testing Guide

### Manual Testing
1. Configure your domain with IndieAuth links
2. Set ADMIN_ME in StarPunk config
3. Use Quill (https://quill.p3k.io) to test posting
4. Verify token caching works (check logs)
5. Test with auth server down (block network)

### Automated Tests
```python
def test_token_verification():
    # Mock external token endpoint
    with responses.RequestsMock() as rsps:
        rsps.add(responses.GET, 'https://tokens.example.com/token',
                 json={'me': 'https://user.com', 'scope': 'create'})

        result = verify_token('test-token', 'https://tokens.example.com/token', 'https://user.com')
        assert result['me'] == 'https://user.com'

def test_auth_server_unreachable():
    # Mock timeout
    with pytest.raises(TokenEndpointError, match="unreachable"):
        verify_token('test-token', 'https://timeout.example.com/token', 'https://user.com')
```

---

## User Documentation Template

### For Users: Setting Up IndieAuth

1. **Add to your website's HTML**:
   ```html
   <link rel="authorization_endpoint" href="https://indielogin.com/auth">
   <link rel="token_endpoint" href="https://tokens.indieauth.com/token">
   <link rel="micropub" href="[YOUR-STARPUNK-URL]/api/micropub">
   ```

2. **Configure StarPunk**:
   ```ini
   ADMIN_ME=https://your-website.com
   ```

3. **Test with a Micropub client**:
   - Visit https://quill.p3k.io
   - Enter your website URL
   - Authorize and post!

---

## Summary

All architectural questions have been answered:

1. **Token Format**: Follow IndieAuth spec exactly
2. **HTML Headers**: Users configure their own domains
3. **Migration**: Keep tables for future use
4. **Errors**: Clear messages about connectivity
5. **Cache**: 5-minute TTL with disable option

The implementation path is clear: remove internal provider code, implement external verification with caching, and provide good error messages. This aligns with StarPunk's philosophy of minimal code and IndieWeb principles.

---

**Ready for Implementation**: All questions answered, examples provided, architecture documented.