# ADR-022: Fix IndieAuth Callback Route Mismatch

## Status
Proposed

## Context
We have discovered a critical routing mismatch in our IndieAuth implementation that causes a 404 error when IndieAuth providers redirect back to our application.

### The Problem
The auth blueprint is currently registered with `url_prefix="/admin"` in `/starpunk/routes/auth.py` line 30:
```python
bp = Blueprint("auth", __name__, url_prefix="/admin")
```

This means all auth routes are actually served under `/admin`:
- `/admin/login` - Login form
- `/admin/callback` - OAuth callback endpoint
- `/admin/logout` - Logout endpoint

However, in `/starpunk/auth.py` lines 325 and 414, the redirect_uri sent to IndieAuth providers is:
```python
redirect_uri = f"{current_app.config['SITE_URL']}auth/callback"
```

This mismatch causes IndieAuth providers to redirect users to `/auth/callback`, which doesn't exist, resulting in a 404 error.

### Current Route Structure
- **Auth Blueprint** (with `/admin` prefix):
  - `/admin/login` - Login form
  - `/admin/callback` - OAuth callback
  - `/admin/logout` - Logout endpoint
- **Admin Blueprint** (with `/admin` prefix):
  - `/admin/` - Dashboard
  - `/admin/new` - Create note
  - `/admin/edit/<id>` - Edit note
  - `/admin/delete/<id>` - Delete note

## Decision
Change the auth blueprint URL prefix from `/admin` to `/auth` to match the redirect_uri being sent to IndieAuth providers.

## Rationale

### 1. Separation of Concerns
Authentication routes (`/auth/*`) should be semantically separate from administration routes (`/admin/*`). This creates a cleaner architecture where:
- `/auth/*` handles authentication flows (login, callback, logout)
- `/admin/*` handles protected administrative functions (dashboard, CRUD operations)

### 2. Standards Compliance
IndieAuth and OAuth2 conventions typically use `/auth/callback` for OAuth callbacks:
- Most OAuth documentation and examples use this pattern
- IndieAuth implementations commonly expect callbacks at `/auth/callback`
- Follows RESTful URL design principles

### 3. Security Benefits
Clear separation provides:
- Easier application of different security policies (rate limiting on auth vs admin)
- Clearer audit trails and access logs
- Reduced cognitive load when reviewing security configurations
- Better principle of least privilege implementation

### 4. Minimal Impact
Analysis of the codebase shows:
- No hardcoded URLs to `/admin/login` in external-facing documentation
- All internal redirects use `url_for('auth.login_form')` which will automatically adjust
- Templates use named routes: `url_for('auth.login_initiate')`, `url_for('auth.logout')`
- No stored auth_state data is tied to the URL path

### 5. Future Flexibility
If we later need public authentication for other features:
- API token generation could live at `/auth/tokens`
- OAuth provider functionality could use `/auth/authorize`
- WebAuthn endpoints could use `/auth/webauthn`
- All auth-related functionality stays organized under `/auth`

## Consequences

### Positive
- **Fixes the immediate bug**: IndieAuth callbacks will work correctly
- **Cleaner architecture**: Proper separation between auth and admin concerns
- **Standards alignment**: Matches common OAuth/IndieAuth patterns
- **No breaking changes**: All internal routes use named endpoints
- **Better organization**: More intuitive URL structure

### Negative
- **Documentation updates needed**: Must update docs showing `/admin/login` paths
- **Potential user confusion**: Users who bookmarked `/admin/login` will get 404
  - Mitigation: Could add a redirect from `/admin/login` to `/auth/login` for transition period

### Migration Requirements
- No database migrations required
- No session invalidation needed
- No configuration changes needed
- Simply update the blueprint registration

## Alternatives Considered

### Alternative 1: Change redirect_uri to `/admin/callback`
**Rejected because:**
- Mixes authentication concerns with administration in URL structure
- Goes against common OAuth/IndieAuth URL patterns
- Less intuitive - callbacks aren't "admin" functions
- Requires changes in two places in `auth.py` (lines 325 and 414)

### Alternative 2: Create a separate `/auth` blueprint just for callback
**Rejected because:**
- Splits related authentication logic across multiple blueprints
- More complex routing configuration
- Harder to maintain - auth logic spread across files
- Violates single responsibility principle at module level

### Alternative 3: Use root-level routes (`/login`, `/callback`, `/logout`)
**Rejected because:**
- Pollutes the root namespace
- No logical grouping of related routes
- Harder to apply auth-specific middleware
- Less scalable as application grows

### Alternative 4: Keep current structure and add redirect
**Rejected because:**
- Doesn't fix the underlying architectural issue
- Adds unnecessary HTTP redirect overhead
- Makes debugging more complex
- Band-aid solution rather than proper fix

## Implementation

### Required Change
Update line 30 in `/home/phil/Projects/starpunk/starpunk/routes/auth.py`:
```python
# From:
bp = Blueprint("auth", __name__, url_prefix="/admin")

# To:
bp = Blueprint("auth", __name__, url_prefix="/auth")
```

### Results
This single change will:
- Make the callback available at `/auth/callback` (matching the redirect_uri)
- Move login to `/auth/login`
- Move logout to `/auth/logout`
- All template references using `url_for()` will automatically resolve correctly

### Optional Transition Support
If desired, add temporary redirects in `starpunk/routes/admin.py`:
```python
@bp.route("/login")
def old_login_redirect():
    """Temporary redirect for bookmarks"""
    return redirect(url_for("auth.login_form"), 301)
```

### Documentation Updates Required
Files to update:
- `/home/phil/Projects/starpunk/TECHNOLOGY-STACK-SUMMARY.md` - Update route table
- `/home/phil/Projects/starpunk/docs/design/phase-4-web-interface.md` - Update route documentation
- `/home/phil/Projects/starpunk/docs/designs/phase-5-quick-reference.md` - Update admin access instructions

## Testing Verification
After implementation:
1. Verify `/auth/login` displays login form
2. Verify `/auth/callback` accepts IndieAuth redirects
3. Verify `/auth/logout` destroys session
4. Verify all admin routes still require authentication
5. Test full IndieAuth flow with real provider

## References
- [IndieAuth Specification](https://www.w3.org/TR/indieauth/) - Section on redirect URIs
- [OAuth 2.0 RFC 6749](https://tools.ietf.org/html/rfc6749) - Section 3.1.2 on redirection endpoints
- [RESTful API Design](https://restfulapi.net/resource-naming/) - URL naming conventions
- Current implementation: `/home/phil/Projects/starpunk/starpunk/routes/auth.py`, `/home/phil/Projects/starpunk/starpunk/auth.py`

---

**Document Version**: 1.0
**Created**: 2025-11-22
**Author**: StarPunk Architecture Team (agent-architect)
**Review Required By**: agent-developer before implementation