Files
Gondulf/docs/decisions/ADR-013-token-verification-endpoint.md
Phil Skentelbery 6bb2a4033f feat(token): implement GET /token for token verification
Implements W3C IndieAuth Section 6.3 token verification endpoint.
The token endpoint now supports both:
- POST: Issue new tokens (authorization code exchange)
- GET: Verify existing tokens (resource server validation)

Changes:
- Added GET handler to /token endpoint
- Extracts Bearer token from Authorization header (RFC 6750)
- Returns JSON with me, client_id, scope
- Returns 401 with WWW-Authenticate for invalid tokens
- 11 new tests covering all verification scenarios

All 533 tests passing. Resolves critical P0 blocker for v1.0.0.

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

Co-Authored-By: Claude <noreply@anthropic.com>
2025-11-25 08:10:47 -07:00

5.9 KiB

ADR-013: Token Verification Endpoint Missing - Critical Compliance Issue

Date: 2025-11-25

Status

Accepted

Context

The user has identified a critical compliance issue with Gondulf's IndieAuth implementation. The W3C IndieAuth specification requires that token endpoints support both POST (for issuing tokens) and GET (for verifying tokens). Currently, Gondulf only implements the POST method for token issuance, returning HTTP 405 (Method Not Allowed) for GET requests.

W3C IndieAuth Specification Requirements

Per the W3C IndieAuth specification Section 6.3 (Token Verification):

The specification states:

"If an external endpoint needs to verify that an access token is valid, it MUST make a GET request to the token endpoint containing an HTTP Authorization header with the Bearer Token according to [RFC6750]."

Example from the specification:

GET https://example.org/token
Authorization: Bearer xxxxxxxx

Required Response Format:

{
  "me": "https://example.com",
  "client_id": "https://client.example.com",
  "scope": "create update"
}

Current Implementation Analysis

  1. Token Endpoint (/home/phil/Projects/Gondulf/src/gondulf/routers/token.py):

    • Only implements @router.post("/token")
    • No GET handler exists
    • Returns 405 Method Not Allowed for GET requests
  2. Token Service (/home/phil/Projects/Gondulf/src/gondulf/services/token_service.py):

    • Has validate_token() method already implemented
    • Returns token metadata (me, client_id, scope)
    • Ready to support verification endpoint
  3. Architecture Documents:

    • Token verification identified in backlog as P1 priority
    • Listed as separate endpoint /token/verify (incorrect)
    • Not included in v1.0.0 scope

Reference Implementation Analysis

IndieLogin.com (PHP reference) only implements POST /token for authentication-only flows. However, this is because IndieLogin is authentication-only and doesn't issue access tokens for resource access. Gondulf DOES issue access tokens, making token verification mandatory.

Decision

This is a CRITICAL COMPLIANCE BUG that MUST be fixed for v1.0.0.

The token endpoint MUST support GET requests for token verification per the W3C IndieAuth specification. This is not optional - it's a core requirement for any implementation that issues access tokens.

Implementation Approach

  1. Same Endpoint, Different Methods:

    • GET /token - Verify token (with Bearer header)
    • POST /token - Issue token (existing functionality)
    • NOT a separate /token/verify endpoint
  2. Implementation Details:

    @router.get("/token")
    async def verify_token(
        authorization: str = Header(None),
        token_service: TokenService = Depends(get_token_service)
    ):
        """
        Verify access token per W3C IndieAuth specification.
    
        GET /token
        Authorization: Bearer {token}
        """
        if not authorization or not authorization.startswith("Bearer "):
            raise HTTPException(401, {"error": "invalid_token"})
    
        token = authorization[7:]  # Remove "Bearer " prefix
        metadata = token_service.validate_token(token)
    
        if not metadata:
            raise HTTPException(401, {"error": "invalid_token"})
    
        return {
            "me": metadata["me"],
            "client_id": metadata["client_id"],
            "scope": metadata["scope"]
        }
    
  3. Error Handling:

    • Missing/invalid Bearer header: 401 Unauthorized
    • Invalid/expired token: 401 Unauthorized
    • Malformed request: 400 Bad Request

Consequences

Positive Consequences

  1. Full Specification Compliance: Gondulf will be fully compliant with W3C IndieAuth
  2. Micropub Compatibility: Resource servers like Micropub endpoints can verify tokens
  3. Interoperability: Any IndieAuth-compliant resource server can work with Gondulf
  4. Minimal Implementation Effort: TokenService already has validation logic

Negative Consequences

  1. Scope Creep: Adds unplanned work to v1.0.0
  2. Testing Required: Need new tests for GET endpoint
  3. Documentation Updates: Must update all token endpoint documentation

Impact Assessment

Severity: CRITICAL Priority: P0 (Blocker for v1.0.0) Effort: Small (1-2 hours)

Without this endpoint:

  • Gondulf is NOT a compliant IndieAuth server
  • Resource servers cannot verify tokens
  • Micropub/Microsub endpoints will fail
  • The entire purpose of issuing access tokens is undermined

Implementation Plan

  1. Immediate Actions:

    • Add GET handler to token endpoint
    • Extract Bearer token from Authorization header
    • Call existing validate_token() method
    • Return required JSON response
  2. Testing Required:

    • Valid token verification
    • Invalid token handling
    • Missing Authorization header
    • Malformed Bearer token
    • Expired token handling
  3. Documentation Updates:

    • Update token endpoint design
    • Add verification examples
    • Update API documentation

Recommendation

APPROVED FOR IMMEDIATE IMPLEMENTATION

This is not a feature request but a critical compliance bug. The token verification endpoint is a mandatory part of the IndieAuth specification for any server that issues access tokens. Without it, Gondulf cannot claim to be an IndieAuth-compliant server.

The implementation is straightforward since all the underlying infrastructure exists. The TokenService already has the validation logic, and we just need to expose it via a GET endpoint that reads the Bearer token from the Authorization header.

This MUST be implemented before v1.0.0 release.