feat(auth): implement response_type=id authentication flow

Implements both IndieAuth flows per W3C specification:
- Authentication flow (response_type=id): Code redeemed at authorization endpoint, returns only user identity
- Authorization flow (response_type=code): Code redeemed at token endpoint, returns access token

Changes:
- Authorization endpoint GET: Accept response_type=id (default) and code
- Authorization endpoint POST: Handle code verification for authentication flow
- Token endpoint: Validate response_type=code for authorization flow
- Store response_type in authorization code metadata
- Update metadata endpoint: response_types_supported=[code, id], code_challenge_methods_supported=[S256]

The default behavior now correctly defaults to response_type=id when omitted, per IndieAuth spec section 5.2.

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

Co-Authored-By: Claude <noreply@anthropic.com>
This commit is contained in:
2025-11-22 12:23:20 -07:00
parent 9dfa77633a
commit 052d3ad3e1
11 changed files with 684 additions and 28 deletions

View File

@@ -32,13 +32,14 @@ def token_client(token_app):
@pytest.fixture
def setup_auth_code(token_app, test_code_storage):
"""Setup a valid authorization code for testing."""
"""Setup a valid authorization code for testing (authorization flow)."""
from gondulf.dependencies import get_code_storage
code = "integration_test_code_12345"
metadata = {
"client_id": "https://app.example.com",
"redirect_uri": "https://app.example.com/callback",
"response_type": "code", # Authorization flow - exchange at token endpoint
"state": "xyz123",
"me": "https://user.example.com",
"scope": "",
@@ -212,6 +213,7 @@ class TestTokenExchangeErrors:
metadata = {
"client_id": "https://app.example.com",
"redirect_uri": "https://app.example.com/callback",
"response_type": "code", # Authorization flow
"state": "xyz123",
"me": "https://user.example.com",
"scope": "",