# ADR-027: IndieAuth Authentication Endpoint Correction

## Status
Accepted

## Context

StarPunk is encountering authentication failures with certain IndieAuth providers (specifically gondulf.thesatelliteoflove.com). After investigation, we discovered that StarPunk is incorrectly using the **token endpoint** for authentication-only flows, when it should be using the **authorization endpoint**.

### The Problem

When attempting to authenticate with gondulf.thesatelliteoflove.com, the provider returns:
```json
{
  "error": "invalid_grant",
  "error_description": "Authorization code must be redeemed at the authorization endpoint"
}
```

StarPunk is currently sending authentication code redemption requests to `/token` when it should be sending them to the authorization endpoint for authentication-only flows.

### IndieAuth Specification Analysis

According to the W3C IndieAuth specification (https://www.w3.org/TR/indieauth/):

1. **Authentication-only flows** (Section 5.4):
   - Used when the client only needs to verify user identity
   - Code redemption happens at the **authorization endpoint**
   - No `grant_type` parameter is used
   - Response contains only `{"me": "user-url"}`

2. **Authorization flows** (Section 6.3):
   - Used when the client needs an access token for API access
   - Code redemption happens at the **token endpoint**
   - Requires `grant_type=authorization_code` parameter
   - Response contains access token and user identity

### Current StarPunk Implementation

StarPunk's current code in `/home/phil/Projects/starpunk/starpunk/auth.py` (lines 410-419):

```python
token_exchange_data = {
    "grant_type": "authorization_code",  # WRONG for authentication-only
    "code": code,
    "client_id": current_app.config["SITE_URL"],
    "redirect_uri": f"{current_app.config['SITE_URL']}auth/callback",
    "code_verifier": code_verifier,  # PKCE verification
}

token_url = f"{current_app.config['INDIELOGIN_URL']}/token"  # WRONG endpoint
```

This implementation has two errors:
1. Uses `/token` endpoint instead of authorization endpoint
2. Includes `grant_type` parameter which should not be present for authentication-only flows

## Decision

StarPunk must correct its IndieAuth authentication implementation to comply with the specification:

1. **Use the authorization endpoint** for code redemption in authentication-only flows
2. **Remove the `grant_type` parameter** from authentication requests
3. **Keep PKCE parameters** (`code_verifier`) as they are still required

## Rationale

### Why This Matters

1. **Standards Compliance**: The IndieAuth specification clearly distinguishes between authentication and authorization flows
2. **Provider Compatibility**: Some providers (like gondulf) strictly enforce the specification
3. **Correct Semantics**: StarPunk only needs to verify admin identity, not obtain an access token

### Authentication vs Authorization

StarPunk's admin login is an **authentication-only** use case:
- We only need to verify the admin's identity (`me` URL)
- We don't need an access token to access external resources
- We create our own session after successful authentication

This is fundamentally different from Micropub client authorization where:
- External clients need access tokens
- Tokens are used to authorize API access
- The token endpoint is the correct choice

## Implementation

### Required Changes

In `/home/phil/Projects/starpunk/starpunk/auth.py`, the `handle_callback` function must be updated:

```python
def handle_callback(code: str, state: str, iss: Optional[str] = None) -> Optional[str]:
    # ... existing state verification code ...

    # Prepare authentication request (NOT token exchange)
    auth_data = {
        # NO grant_type parameter for authentication-only flows
        "code": code,
        "client_id": current_app.config["SITE_URL"],
        "redirect_uri": f"{current_app.config['SITE_URL']}auth/callback",
        "code_verifier": code_verifier,  # PKCE verification still required
    }

    # Use authorization endpoint (NOT token endpoint)
    # The same endpoint used for the initial authorization request
    auth_url = f"{current_app.config['INDIELOGIN_URL']}/auth"  # or /authorize

    # Exchange code for identity (authentication-only)
    response = httpx.post(
        auth_url,
        data=auth_data,
        timeout=10.0,
    )

    # Response will be: {"me": "https://user.example.com"}
    # NOT an access token response
```

### Endpoint Discovery Consideration

IndieAuth providers may use different paths for their authorization endpoint:
- IndieLogin.com uses `/auth`
- Some providers use `/authorize`
- The gondulf provider appears to use its root domain as the authorization endpoint

The correct approach is to:
1. Discover the authorization endpoint from the provider's metadata
2. Use the same endpoint for both authorization initiation and code redemption
3. Store the discovered endpoint during the initial authorization request

## Consequences

### Positive
- **Specification Compliance**: Correctly implements IndieAuth authentication flow
- **Provider Compatibility**: Works with strict IndieAuth implementations
- **Semantic Correctness**: Uses the right flow for the use case

### Negative
- **Breaking Change**: May affect compatibility with providers that accept both endpoints
- **Testing Required**: Need to verify with multiple IndieAuth providers

### Migration Impact
- Existing sessions remain valid (no database changes)
- Only affects new login attempts
- Should be transparent to users

## Testing Strategy

Test with multiple IndieAuth providers:
1. **IndieLogin.com** - Current provider (should continue working)
2. **gondulf.thesatelliteoflove.com** - Strict implementation
3. **tokens.indieauth.com** - Token-only endpoint (should fail for auth)
4. **Self-hosted implementations** - Various compliance levels

## Alternatives Considered

### Alternative 1: Support Both Endpoints
Attempt token endpoint first, fall back to authorization endpoint on failure.
- **Pros**: Maximum compatibility
- **Cons**: Not specification-compliant, adds complexity
- **Verdict**: Rejected - violates standards

### Alternative 2: Make Endpoint Configurable
Allow admin to configure which endpoint to use.
- **Pros**: Flexible for different providers
- **Cons**: Confusing for users, not needed if we follow spec
- **Verdict**: Rejected - specification is clear

### Alternative 3: Always Use Token Endpoint
Continue current implementation, document incompatibility.
- **Pros**: No code changes needed
- **Cons**: Violates specification, limits provider choice
- **Verdict**: Rejected - incorrect implementation

## References

- [IndieAuth Specification Section 5.4](https://www.w3.org/TR/indieauth/#authentication-response): Authorization Code Verification for authentication flows
- [IndieAuth Specification Section 6.3](https://www.w3.org/TR/indieauth/#token-response): Token Endpoint for authorization flows
- [IndieAuth Authentication vs Authorization](https://indieweb.org/IndieAuth#Authentication_vs_Authorization): Community documentation
- [ADR-021: IndieAuth Provider Strategy](/home/phil/Projects/starpunk/docs/decisions/ADR-021-indieauth-provider-strategy.md): Related architectural decision

---

**Document Version**: 1.0
**Created**: 2025-11-22
**Author**: StarPunk Architecture Team
**Status**: Accepted