Implements complete W3C IndieAuth Section 3.2 client identifier validation including: - Fragment rejection - HTTP scheme support for localhost/loopback only - Username/password component rejection - Non-loopback IP address rejection - Path traversal prevention (.. and . segments) - Hostname case normalization - Default port removal (80/443) - Path component enforcement All 75 validation tests passing with 99% coverage. 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude <noreply@anthropic.com>
3.6 KiB
ADR-012: Client ID Validation Compliance
Date: 2025-11-24
Status
Accepted
Context
During pre-release compliance review, we discovered that Gondulf's client_id validation is not fully compliant with the W3C IndieAuth specification Section 3.2. The current implementation in normalize_client_id() only performs basic HTTPS validation and port normalization, missing several critical requirements:
Non-compliance issues identified:
- Rejects HTTP URLs even for localhost (spec allows HTTP for loopback addresses)
- Accepts fragments in URLs (spec explicitly forbids fragments)
- Accepts username/password in URLs (spec forbids user info components)
- Accepts non-loopback IP addresses (spec only allows 127.0.0.1 and [::1])
- Accepts path traversal segments (. and ..)
- Does not normalize hostnames to lowercase
- Does not ensure path component exists
These violations could lead to:
- Legitimate local development clients being rejected (HTTP localhost)
- Security vulnerabilities (credential exposure, path traversal)
- Interoperability issues with compliant IndieAuth clients
- Confusion about client identity (fragments, case sensitivity)
Decision
We will implement complete W3C IndieAuth specification compliance for client_id validation by:
-
Separating validation from normalization: Create a new
validate_client_id()function that performs all specification checks, separate from the normalization logic. -
Supporting HTTP for localhost: Allow HTTP scheme for localhost, 127.0.0.1, and [::1] to support local development while maintaining HTTPS requirement for production domains.
-
Rejecting non-compliant URLs: Explicitly reject URLs with fragments, credentials, non-loopback IPs, and path traversal segments.
-
Providing specific error messages: Return detailed error messages for each validation failure to help developers understand what needs to be fixed.
-
Maintaining backward compatibility: The stricter validation only rejects URLs that were already non-compliant with the specification. Valid client_ids continue to work.
Consequences
Positive Consequences
-
Full specification compliance: Gondulf will correctly handle all client_ids as defined by W3C IndieAuth specification.
-
Improved security: Rejecting credentials, path traversal, and non-loopback IPs prevents potential security vulnerabilities.
-
Better developer experience: Clear error messages help developers quickly fix client_id issues.
-
Local development support: HTTP localhost support enables easier local testing and development.
-
Interoperability: Any compliant IndieAuth client will work with Gondulf.
Negative Consequences
-
Breaking change for non-compliant clients: Clients using non-compliant client_ids (e.g., with fragments or credentials) will be rejected. However, these were already violating the specification.
-
Slightly more complex validation: The validation logic is more comprehensive, but this complexity is contained within well-documented functions.
-
Additional testing burden: More test cases are needed to cover all validation rules.
Implementation Notes
- The validation logic is implemented as a pure function with no side effects
- Normalization happens after validation to ensure only valid client_ids are normalized
- Both authorization and token endpoints use the same validation logic
- Error messages follow OAuth 2.0 error response format
This decision ensures Gondulf is a fully compliant IndieAuth server that can interoperate with any specification-compliant client while maintaining security and providing a good developer experience.