Files
StarPunk/docs/decisions/ADR-022-indieauth-authentication-endpoint-correction.md
Phil Skentelbery a6f3fbaae4 fix: Use authorization endpoint for IndieAuth code verification (v0.9.4)
IndieAuth authentication-only flows should redeem the code at the
authorization endpoint, not the token endpoint. The token endpoint
is only for authorization flows that need access tokens.

- Remove grant_type parameter (only needed for token flows)
- Change endpoint from /token to /authorize
- Update debug logging to reflect code verification flow

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude <noreply@anthropic.com>
2025-11-22 19:19:37 -07:00

188 lines
7.2 KiB
Markdown

# ADR-022: 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