Files
Gondulf/src/gondulf/routers/metadata.py
Phil Skentelbery 052d3ad3e1 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>
2025-11-22 12:23:20 -07:00

49 lines
1.5 KiB
Python

"""OAuth 2.0 Authorization Server Metadata endpoint (RFC 8414)."""
import json
import logging
from fastapi import APIRouter, Depends, Response
from gondulf.config import Config
from gondulf.dependencies import get_config
logger = logging.getLogger("gondulf.metadata")
router = APIRouter()
@router.get("/.well-known/oauth-authorization-server")
async def get_metadata(config: Config = Depends(get_config)) -> Response:
"""
OAuth 2.0 Authorization Server Metadata (RFC 8414).
Returns server capabilities for IndieAuth client discovery.
This endpoint is publicly accessible and cacheable.
Returns:
Response: JSON response with server metadata and Cache-Control header
"""
logger.debug("Metadata endpoint requested")
metadata = {
"issuer": config.BASE_URL,
"authorization_endpoint": f"{config.BASE_URL}/authorize",
"token_endpoint": f"{config.BASE_URL}/token",
"response_types_supported": ["code", "id"],
"grant_types_supported": ["authorization_code"],
"code_challenge_methods_supported": ["S256"],
"token_endpoint_auth_methods_supported": ["none"],
"revocation_endpoint_auth_methods_supported": ["none"],
"scopes_supported": []
}
logger.debug(f"Returning metadata for issuer: {config.BASE_URL}")
return Response(
content=json.dumps(metadata, indent=2),
media_type="application/json",
headers={
"Cache-Control": "public, max-age=86400"
}
)