Files
StarPunk/docs/design/hotfix/2025-12-17-indieauth-pkce-endpoint-discovery-hotfix-implementation-report.md
Phil Skentelbery 2bd971f3d6 fix(auth): Implement IndieAuth endpoint discovery per W3C spec
BREAKING: Removes INDIELOGIN_URL config - endpoints are now properly
discovered from user's profile URL as required by W3C IndieAuth spec.

- auth.py: Uses discover_endpoints() to find authorization_endpoint
- config.py: Deprecation warning for obsolete INDIELOGIN_URL setting
- auth_external.py: Relaxed validation (allows auth-only flows)
- tests: Updated to mock endpoint discovery

This fixes a regression where admin login was hardcoded to use
indielogin.com instead of respecting the user's declared endpoints.

Version: 1.5.0-hotfix.1

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

Co-Authored-By: Claude <noreply@anthropic.com>
2025-12-17 13:52:36 -07:00

7.8 KiB

IndieAuth Endpoint Discovery Hotfix - Implementation Report

Date: 2025-12-17 Type: Production Hotfix Priority: Critical Status: Implementation Complete

Summary

Successfully implemented the IndieAuth endpoint discovery hotfix as specified in the design document. The authentication flow now correctly discovers endpoints from the user's profile URL per the W3C IndieAuth specification, instead of hardcoding the indielogin.com service.

Implementation Steps

All implementation steps were completed successfully:

Step 1: Update starpunk/config.py - Remove INDIELOGIN_URL

  • Removed INDIELOGIN_URL config line (previously line 37)
  • Added deprecation warning for users still setting INDIELOGIN_URL in environment
  • Warning directs users to remove the deprecated config

Step 2: Update starpunk/auth.py - Add imports and use endpoint discovery

  • Added imports: discover_endpoints, DiscoveryError, normalize_url from starpunk.auth_external
  • Rewrote initiate_login():
    • Now discovers authorization_endpoint from the user's profile URL
    • Uses discovered endpoint instead of hardcoded INDIELOGIN_URL
    • Raises DiscoveryError if endpoint discovery fails or no authorization_endpoint found
  • Rewrote handle_callback():
    • Discovers authorization_endpoint from ADMIN_ME profile
    • Uses authorization_endpoint for authentication-only flow (per IndieAuth spec)
    • Does NOT include grant_type parameter (not needed for auth-only flows)
    • Uses normalize_url() for URL comparison to handle trailing slashes and case differences

Step 3: Update starpunk/auth_external.py - Relax endpoint validation

  • Changed endpoint validation in _fetch_and_parse():
    • Now requires at least one endpoint (authorization_endpoint OR token_endpoint)
    • Previously required token_endpoint to be present
    • This allows profiles with only authorization_endpoint to work for login
    • Micropub will still require token_endpoint and fail gracefully with 401

Step 4: Update starpunk/routes/auth.py - Import and handle DiscoveryError

  • Added import for DiscoveryError from starpunk.auth_external
  • Added exception handler in login_initiate():
    • Catches DiscoveryError
    • Logs technical details at ERROR level
    • Shows user-friendly message: "Unable to verify your profile URL. Please check that it's correct and try again."
    • Redirects back to login form

Step 5: Update tests/test_auth.py - Mock discover_endpoints()

  • Removed INDIELOGIN_URL from test app fixture
  • Updated all tests that call initiate_login() or handle_callback():
    • Added @patch("starpunk.auth.discover_endpoints") decorator
    • Mock returns both authorization_endpoint and token_endpoint
    • Updated assertions to check for discovered endpoint instead of indielogin.com
  • Tests updated:
    • TestInitiateLogin.test_initiate_login_success
    • TestInitiateLogin.test_initiate_login_stores_state
    • TestHandleCallback.test_handle_callback_success
    • TestHandleCallback.test_handle_callback_unauthorized_user
    • TestHandleCallback.test_handle_callback_indielogin_error
    • TestHandleCallback.test_handle_callback_no_identity
    • TestLoggingIntegration.test_initiate_login_logs_at_debug
    • TestLoggingIntegration.test_initiate_login_info_level
    • TestLoggingIntegration.test_handle_callback_logs_http_details

Step 6: Update tests/test_auth_external.py - Fix error message

  • Updated test_discover_endpoints_no_token_endpoint:
    • Changed assertion from "No token endpoint found" to "No IndieAuth endpoints found"
    • Matches new relaxed validation error message

Step 7: Run tests to verify implementation

  • All 51 tests in tests/test_auth.py pass
  • All 35 tests in tests/test_auth_external.py pass
  • All 32 tests in tests/test_routes_admin.py pass
  • No regressions detected

Files Modified

File Lines Changed Description
starpunk/config.py 9 added, 1 removed Removed INDIELOGIN_URL, added deprecation warning
starpunk/auth.py 1 added, 84 replaced Added imports, rewrote initiate_login() and handle_callback()
starpunk/auth_external.py 6 replaced Relaxed endpoint validation
starpunk/routes/auth.py 5 added Added DiscoveryError import and exception handling
tests/test_auth.py 1 removed, 43 modified Removed INDIELOGIN_URL from fixture, added mocks
tests/test_auth_external.py 2 modified Updated error message assertion

Key Implementation Details

Authorization Endpoint Usage

Per IndieAuth spec and architect clarifications:

  • Authentication-only flows POST to the authorization_endpoint (not token_endpoint)
  • The grant_type parameter is NOT included (only for access token flows)
  • This differs from the previous implementation which incorrectly used indielogin.com's endpoints

URL Normalization

The implementation now uses normalize_url() when comparing the returned 'me' URL with ADMIN_ME:

Error Handling

  • Discovery failures are caught and logged at ERROR level
  • User-facing error message is simplified and friendly
  • Technical details remain in logs for debugging

Backward Compatibility

  • Deprecation warning added for INDIELOGIN_URL environment variable
  • Existing .env files with INDIELOGIN_URL will log a warning but continue to work
  • Users are instructed to remove the deprecated config

Testing Results

Unit Tests

  • tests/test_auth.py: 51/51 passed
  • tests/test_auth_external.py: 35/35 passed
  • tests/test_routes_admin.py: 32/32 passed

Integration

All modified tests now correctly mock endpoint discovery and validate the new behavior.

Issues Encountered

No significant issues encountered during implementation. The design document was thorough and all architect clarifications were addressed:

  1. Import placement - Moved to top-level as specified
  2. URL normalization - Included as intentional bugfix
  3. Endpoint selection - Used authorization_endpoint for auth-only flows
  4. Validation relaxation - Allowed profiles with only authorization_endpoint
  5. Test strategy - Mocked discover_endpoints() and removed INDIELOGIN_URL
  6. grant_type parameter - Correctly omitted for auth-only flows
  7. Error messages - Simplified user-facing messages

Next Steps

  1. Manual testing recommended:

    • Test login flow with actual IndieAuth profile
    • Verify endpoint discovery logs appear
    • Test with profiles that have custom endpoints
    • Verify error message appears for profiles without endpoints
  2. Deployment:

    • Update production .env to remove INDIELOGIN_URL (optional - will show warning)
    • Deploy changes
    • Monitor logs for "Discovered authorization_endpoint" messages
    • Verify login works for admin user
  3. Documentation:

    • Update CHANGELOG.md with hotfix entry
    • Consider adding migration guide if needed

Verification Checklist

  • All specified files modified
  • All code changes follow architect's design exactly
  • Tests updated and passing
  • Error messages user-friendly
  • Logging appropriate for debugging
  • URL normalization implemented
  • Endpoint validation relaxed correctly
  • No regressions in existing tests
  • Implementation report created

Conclusion

The hotfix has been successfully implemented according to the architect's design. The authentication flow now correctly implements the W3C IndieAuth specification for endpoint discovery. All tests pass and no regressions were detected.

The critical production bug preventing user login should be resolved once this code is deployed.


Developer: Claude (Fullstack Developer Subagent) Date Completed: 2025-12-17 Ready for Review: Yes