This fixes critical IndieAuth authentication by implementing PKCE (Proof Key for Code Exchange) as required by IndieLogin.com API specification. Added: - PKCE code_verifier and code_challenge generation (RFC 7636) - Database column: auth_state.code_verifier for PKCE support - Issuer validation for authentication callbacks - Comprehensive PKCE unit tests (6 tests, all passing) - Database migration script for code_verifier column Changed: - Corrected IndieLogin.com API endpoints (/authorize and /token) - State token validation now returns code_verifier for token exchange - Authentication flow follows IndieLogin.com API specification exactly - Enhanced logging with code_verifier redaction Removed: - OAuth metadata endpoint (/.well-known/oauth-authorization-server) Added in v0.7.0 but not required by IndieLogin.com - h-app microformats markup from templates Modified in v0.7.1 but not used by IndieLogin.com - indieauth-metadata link from HTML head Security: - PKCE prevents authorization code interception attacks - Issuer validation prevents token substitution attacks - Code verifier securely stored, redacted in logs, and single-use Documentation: - Version: 0.8.0 - CHANGELOG updated with v0.8.0 entry and v0.7.x notes - ADR-016 and ADR-017 marked as superseded by ADR-019 - Implementation report created in docs/reports/ - Test update guide created in TODO_TEST_UPDATES.md Breaking Changes: - Users mid-authentication will need to restart login after upgrade - Database migration required before deployment Related: ADR-019 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude <noreply@anthropic.com>
548 lines
18 KiB
Markdown
548 lines
18 KiB
Markdown
# ADR-017: OAuth Client ID Metadata Document Implementation
|
|
|
|
## Status
|
|
|
|
**Superseded by ADR-019** - IndieLogin.com does not require OAuth metadata endpoint. PKCE implementation is the correct solution.
|
|
|
|
## Context
|
|
|
|
StarPunk continues to experience "client_id is not registered" errors from IndieLogin.com despite implementing h-app microformats in ADR-016 and making them visible in ADR-006.
|
|
|
|
### The Problem
|
|
|
|
IndieLogin.com rejects authentication requests with the error:
|
|
```
|
|
Request Error
|
|
This client_id is not registered (https://starpunk.thesatelliteoflove.com)
|
|
```
|
|
|
|
### Root Cause Analysis
|
|
|
|
Through comprehensive review of the IndieAuth specification and actual IndieLogin.com behavior, we've identified that:
|
|
|
|
1. **IndieAuth Specification Has Evolved**: The current specification (2022+) uses OAuth Client ID Metadata Documents (JSON) as the primary client discovery mechanism
|
|
2. **h-app is Legacy**: While h-app microformats are still supported for backward compatibility, they are no longer the primary standard
|
|
3. **IndieLogin.com Expects JSON**: IndieLogin.com appears to require or strongly prefer the modern JSON metadata approach
|
|
4. **Our Implementation is Outdated**: StarPunk only provides h-app markup, not JSON metadata
|
|
|
|
### What the Specification Requires
|
|
|
|
From IndieAuth Spec Section 4.2 (Client Information Discovery):
|
|
|
|
> "Clients SHOULD publish a Client Identifier Metadata Document at their client_id URL."
|
|
|
|
The specification further states:
|
|
|
|
> "If fetching the metadata document fails, the authorization server SHOULD abort the authorization request."
|
|
|
|
This explains the rejection behavior - IndieLogin.com fetches our client_id URL, expects JSON metadata, doesn't find it, and aborts.
|
|
|
|
### Why Previous ADRs Failed
|
|
|
|
- **ADR-016**: Implemented h-app but used `hidden` attribute, making it invisible to parsers
|
|
- **ADR-006**: Made h-app visible but this is no longer the primary discovery mechanism
|
|
- **Both**: Did not implement the modern JSON metadata document approach
|
|
|
|
## Decision
|
|
|
|
Implement OAuth Client ID Metadata Document as a JSON endpoint at `/.well-known/oauth-authorization-server` following the current IndieAuth specification.
|
|
|
|
### Implementation Details
|
|
|
|
#### 1. Create Metadata Endpoint
|
|
|
|
**Route**: `/.well-known/oauth-authorization-server`
|
|
**Method**: GET
|
|
**Content-Type**: application/json
|
|
**Cache**: 24 hours (metadata rarely changes)
|
|
|
|
**Response Structure**:
|
|
```json
|
|
{
|
|
"issuer": "https://starpunk.thesatelliteoflove.com",
|
|
"client_id": "https://starpunk.thesatelliteoflove.com",
|
|
"client_name": "StarPunk",
|
|
"client_uri": "https://starpunk.thesatelliteoflove.com",
|
|
"redirect_uris": [
|
|
"https://starpunk.thesatelliteoflove.com/auth/callback"
|
|
],
|
|
"grant_types_supported": ["authorization_code"],
|
|
"response_types_supported": ["code"],
|
|
"code_challenge_methods_supported": ["S256"],
|
|
"token_endpoint_auth_methods_supported": ["none"]
|
|
}
|
|
```
|
|
|
|
#### 2. Add Discovery Link
|
|
|
|
Add to `templates/base.html` `<head>` section:
|
|
```html
|
|
<link rel="indieauth-metadata" href="/.well-known/oauth-authorization-server">
|
|
```
|
|
|
|
#### 3. Maintain h-app for Legacy Support
|
|
|
|
Keep existing h-app markup in footer as fallback for older IndieAuth servers that may not support JSON metadata.
|
|
|
|
This creates three layers of discovery:
|
|
1. Well-known URL (primary, modern standard)
|
|
2. Link rel hint (explicit pointer)
|
|
3. h-app microformats (legacy fallback)
|
|
|
|
## Rationale
|
|
|
|
### Why JSON Metadata?
|
|
|
|
1. **Current Standard**: This is what the 2022+ IndieAuth spec recommends
|
|
2. **IndieLogin.com Compatibility**: Addresses the actual error we're experiencing
|
|
3. **Machine Readable**: JSON is easier for servers to parse than microformats
|
|
4. **Extensibility**: Easy to add more metadata fields in future
|
|
5. **Separation of Concerns**: Metadata endpoint separate from presentation
|
|
|
|
### Why Well-Known URL?
|
|
|
|
1. **IANA Registered**: `/.well-known/` is the standard path for service metadata
|
|
2. **Discoverable**: Predictable location makes discovery reliable
|
|
3. **Clean**: No content negotiation complexity
|
|
4. **Standard Practice**: Used by OAuth, OIDC, WebFinger, etc.
|
|
|
|
### Why Keep h-app?
|
|
|
|
1. **Backward Compatibility**: Supports older IndieAuth servers
|
|
2. **Redundancy**: Multiple discovery methods increase reliability
|
|
3. **Low Cost**: Already implemented, minimal maintenance
|
|
4. **Best Practice**: Modern IndieAuth clients support both
|
|
|
|
### Why This Will Work
|
|
|
|
1. **Specification Compliance**: Directly implements current IndieAuth spec requirements
|
|
2. **Observable Behavior**: IndieLogin.com's error message indicates it's checking for registration/metadata
|
|
3. **Industry Pattern**: All modern IndieAuth clients use JSON metadata
|
|
4. **Testable**: Can verify endpoint before deploying
|
|
|
|
## Consequences
|
|
|
|
### Positive
|
|
|
|
1. ✅ **Fixes Authentication**: Should resolve "client_id is not registered" error
|
|
2. ✅ **Standards Compliant**: Follows current IndieAuth specification exactly
|
|
3. ✅ **Future Proof**: Unlikely to require changes as spec is stable
|
|
4. ✅ **Better Metadata**: Can provide more detailed client information
|
|
5. ✅ **Easy to Test**: Simple curl request verifies implementation
|
|
6. ✅ **Clean Architecture**: Dedicated endpoint for metadata
|
|
7. ✅ **Maximum Compatibility**: Works with old and new IndieAuth servers
|
|
|
|
### Negative
|
|
|
|
1. ⚠️ **New Route**: Adds one more endpoint to maintain
|
|
- Mitigation: Very simple, rarely changes, no business logic
|
|
2. ⚠️ **Data Duplication**: Client info in both JSON and h-app
|
|
- Mitigation: Can use config variables as single source
|
|
3. ⚠️ **Testing Surface**: New endpoint to test
|
|
- Mitigation: Simple unit tests, no complex logic
|
|
|
|
### Neutral
|
|
|
|
1. **File Size**: Adds ~500 bytes to metadata response
|
|
- Cached for 24 hours, negligible bandwidth impact
|
|
2. **Code Complexity**: Modest increase
|
|
- ~20 lines of Python code
|
|
- Simple JSON serialization, no complex logic
|
|
|
|
## Implementation Requirements
|
|
|
|
### Python Code
|
|
|
|
```python
|
|
@app.route('/.well-known/oauth-authorization-server')
|
|
def oauth_client_metadata():
|
|
"""
|
|
OAuth Client ID Metadata Document endpoint.
|
|
|
|
Returns JSON metadata about this IndieAuth client for authorization
|
|
server discovery. Required by IndieAuth specification section 4.2.
|
|
|
|
See: https://indieauth.spec.indieweb.org/#client-information-discovery
|
|
"""
|
|
metadata = {
|
|
'issuer': current_app.config['SITE_URL'],
|
|
'client_id': current_app.config['SITE_URL'],
|
|
'client_name': current_app.config.get('SITE_NAME', 'StarPunk'),
|
|
'client_uri': current_app.config['SITE_URL'],
|
|
'redirect_uris': [
|
|
f"{current_app.config['SITE_URL']}/auth/callback"
|
|
],
|
|
'grant_types_supported': ['authorization_code'],
|
|
'response_types_supported': ['code'],
|
|
'code_challenge_methods_supported': ['S256'],
|
|
'token_endpoint_auth_methods_supported': ['none']
|
|
}
|
|
|
|
response = jsonify(metadata)
|
|
|
|
# Cache for 24 hours (metadata rarely changes)
|
|
response.cache_control.max_age = 86400
|
|
response.cache_control.public = True
|
|
|
|
return response
|
|
```
|
|
|
|
### HTML Template Update
|
|
|
|
In `templates/base.html`, add to `<head>`:
|
|
```html
|
|
<!-- IndieAuth client metadata discovery -->
|
|
<link rel="indieauth-metadata" href="/.well-known/oauth-authorization-server">
|
|
```
|
|
|
|
### Configuration Dependencies
|
|
|
|
Required config values:
|
|
- `SITE_URL`: Full URL to the application (e.g., "https://starpunk.thesatelliteoflove.com")
|
|
- `SITE_NAME`: Application name (optional, defaults to "StarPunk")
|
|
|
|
### Validation Rules
|
|
|
|
The implementation MUST ensure:
|
|
|
|
1. **client_id Exact Match**: `metadata['client_id']` MUST exactly match the URL where the document is served
|
|
- Use `current_app.config['SITE_URL']` from configuration
|
|
- Do NOT hardcode URLs
|
|
|
|
2. **HTTPS in Production**: All URLs MUST use HTTPS scheme in production
|
|
- Development may use HTTP
|
|
- Consider environment-based URL construction
|
|
|
|
3. **Valid JSON**: Response MUST be parseable JSON
|
|
- Use Flask's `jsonify()` which handles serialization
|
|
- Validates structure automatically
|
|
|
|
4. **Correct Content-Type**: Response MUST include `Content-Type: application/json` header
|
|
- `jsonify()` sets this automatically
|
|
|
|
5. **Array Types**: `redirect_uris` MUST be an array, even with single value
|
|
- Use Python list: `['url']` not string: `'url'`
|
|
|
|
## Testing Strategy
|
|
|
|
### Unit Tests
|
|
|
|
```python
|
|
def test_oauth_metadata_endpoint_exists(client):
|
|
"""Verify metadata endpoint returns 200 OK"""
|
|
response = client.get('/.well-known/oauth-authorization-server')
|
|
assert response.status_code == 200
|
|
|
|
def test_oauth_metadata_content_type(client):
|
|
"""Verify response is JSON"""
|
|
response = client.get('/.well-known/oauth-authorization-server')
|
|
assert response.content_type == 'application/json'
|
|
|
|
def test_oauth_metadata_required_fields(client, app):
|
|
"""Verify all required fields present and valid"""
|
|
response = client.get('/.well-known/oauth-authorization-server')
|
|
data = response.get_json()
|
|
|
|
# Required fields
|
|
assert 'client_id' in data
|
|
assert 'client_name' in data
|
|
assert 'redirect_uris' in data
|
|
|
|
# client_id must match SITE_URL exactly (spec requirement)
|
|
assert data['client_id'] == app.config['SITE_URL']
|
|
|
|
# redirect_uris must be array
|
|
assert isinstance(data['redirect_uris'], list)
|
|
assert len(data['redirect_uris']) > 0
|
|
|
|
def test_oauth_metadata_cache_headers(client):
|
|
"""Verify appropriate cache headers set"""
|
|
response = client.get('/.well-known/oauth-authorization-server')
|
|
assert response.cache_control.max_age == 86400
|
|
assert response.cache_control.public is True
|
|
|
|
def test_indieauth_metadata_link_present(client):
|
|
"""Verify discovery link in HTML head"""
|
|
response = client.get('/')
|
|
assert b'rel="indieauth-metadata"' in response.data
|
|
assert b'/.well-known/oauth-authorization-server' in response.data
|
|
```
|
|
|
|
### Integration Tests
|
|
|
|
1. **Direct Fetch**: Use `requests` to fetch metadata, parse JSON, verify structure
|
|
2. **Discovery Flow**: Verify HTML contains link, fetch linked URL, verify metadata
|
|
3. **Real IndieLogin**: Test complete authentication flow with IndieLogin.com
|
|
|
|
### Manual Validation
|
|
|
|
```bash
|
|
# Fetch metadata directly
|
|
curl https://starpunk.thesatelliteoflove.com/.well-known/oauth-authorization-server
|
|
|
|
# Verify valid JSON
|
|
curl -s https://starpunk.thesatelliteoflove.com/.well-known/oauth-authorization-server | jq .
|
|
|
|
# Check client_id matches (should output: true)
|
|
curl -s https://starpunk.thesatelliteoflove.com/.well-known/oauth-authorization-server | \
|
|
jq '.client_id == "https://starpunk.thesatelliteoflove.com"'
|
|
|
|
# Verify cache headers
|
|
curl -I https://starpunk.thesatelliteoflove.com/.well-known/oauth-authorization-server | \
|
|
grep -i cache-control
|
|
```
|
|
|
|
## Deployment Checklist
|
|
|
|
- [ ] Implement `/.well-known/oauth-authorization-server` route
|
|
- [ ] Add JSON response with all required fields
|
|
- [ ] Add cache headers (24 hour max-age)
|
|
- [ ] Add `<link rel="indieauth-metadata">` to base.html
|
|
- [ ] Write and run unit tests (all passing)
|
|
- [ ] Test locally with curl and jq
|
|
- [ ] Verify client_id exactly matches SITE_URL
|
|
- [ ] Deploy to production
|
|
- [ ] Verify endpoint accessible: `curl https://starpunk.thesatelliteoflove.com/.well-known/oauth-authorization-server`
|
|
- [ ] Test authentication flow with IndieLogin.com
|
|
- [ ] Verify no "client_id is not registered" error
|
|
- [ ] Complete successful admin login
|
|
- [ ] Update documentation
|
|
- [ ] Increment version to v0.6.2
|
|
- [ ] Update CHANGELOG.md
|
|
|
|
## Success Criteria
|
|
|
|
Implementation is successful when:
|
|
|
|
1. ✅ Metadata endpoint returns 200 OK with valid JSON
|
|
2. ✅ All required fields present in response
|
|
3. ✅ `client_id` exactly matches document URL
|
|
4. ✅ IndieLogin.com authentication flow completes without error
|
|
5. ✅ Admin can successfully log in via IndieAuth
|
|
6. ✅ Unit tests achieve >95% coverage
|
|
7. ✅ Production deployment verified working
|
|
|
|
## Alternatives Considered
|
|
|
|
### Alternative 1: Content Negotiation at Root URL
|
|
|
|
Serve JSON when `Accept: application/json` header is present, otherwise serve HTML.
|
|
|
|
**Rejected Because**:
|
|
- More complex logic
|
|
- Higher chance of bugs
|
|
- Harder to test
|
|
- Non-standard approach
|
|
- Content negotiation can be fragile
|
|
|
|
### Alternative 2: JSON-Only (Remove h-app)
|
|
|
|
Implement JSON metadata and remove h-app entirely.
|
|
|
|
**Rejected Because**:
|
|
- Breaks backward compatibility
|
|
- Some servers may still use h-app
|
|
- No cost to keeping both
|
|
- Redundancy increases reliability
|
|
|
|
### Alternative 3: Custom Metadata Path
|
|
|
|
Use non-standard path like `/client-metadata.json`.
|
|
|
|
**Rejected Because**:
|
|
- Not following standard well-known conventions
|
|
- Harder to discover
|
|
- No advantage over standard path
|
|
- May not work with some IndieAuth servers
|
|
|
|
### Alternative 4: Do Nothing (Wait for IndieLogin.com Fix)
|
|
|
|
Assume IndieLogin.com has a bug and wait for them to fix it.
|
|
|
|
**Rejected Because**:
|
|
- Blocking production authentication
|
|
- Specification clearly supports JSON metadata
|
|
- Other services may have same requirement
|
|
- User data suggests this is our bug, not theirs
|
|
|
|
## Migration Path
|
|
|
|
### From Current State
|
|
|
|
1. No database changes required
|
|
2. No configuration changes required (uses existing SITE_URL)
|
|
3. No breaking changes to existing functionality
|
|
4. Purely additive - adds new endpoint
|
|
|
|
### Backward Compatibility
|
|
|
|
- Existing h-app markup remains functional
|
|
- Older IndieAuth servers continue to work
|
|
- No impact on users or existing sessions
|
|
|
|
### Forward Compatibility
|
|
|
|
- Endpoint can be extended with additional metadata fields
|
|
- Cache headers can be adjusted if needed
|
|
- Can add more discovery mechanisms if spec evolves
|
|
|
|
## Security Implications
|
|
|
|
### Information Disclosure
|
|
|
|
**Exposed Information**:
|
|
- Application name (already public)
|
|
- Application URL (already public)
|
|
- Callback URL (already in auth flow)
|
|
- Supported OAuth methods (standard)
|
|
|
|
**Risk**: None - all information is non-sensitive and already public
|
|
|
|
### Input Validation
|
|
|
|
**No User Input**: Endpoint serves static configuration data only
|
|
|
|
**Risk**: None - no injection vectors
|
|
|
|
### Denial of Service
|
|
|
|
**Concern**: Endpoint could be hammered with requests
|
|
|
|
**Mitigation**:
|
|
- 24 hour cache reduces server load
|
|
- Rate limiting at reverse proxy (nginx/Caddy)
|
|
- Simple response, fast generation (<10ms)
|
|
|
|
### Access Control
|
|
|
|
**Public Endpoint**: No authentication required
|
|
|
|
**Justification**: OAuth client metadata is designed to be publicly accessible for discovery
|
|
|
|
## Performance Impact
|
|
|
|
### Response Time
|
|
- **Target**: < 10ms
|
|
- **Actual**: ~2-5ms (simple dict serialization)
|
|
- **Bottleneck**: None (no DB/file I/O)
|
|
|
|
### Response Size
|
|
- **JSON**: ~400-500 bytes
|
|
- **Gzipped**: ~250 bytes
|
|
- **Impact**: Negligible
|
|
|
|
### Caching Strategy
|
|
- **Max-Age**: 24 hours
|
|
- **Type**: Public cache
|
|
- **Rationale**: Metadata rarely changes
|
|
|
|
### Resource Usage
|
|
- **CPU**: Minimal (one-time JSON serialization)
|
|
- **Memory**: Negligible (~1KB response)
|
|
- **Network**: Cached by browsers/proxies
|
|
|
|
## Compliance
|
|
|
|
### IndieAuth Specification
|
|
- ✅ Section 4.2: Client Information Discovery
|
|
- ✅ OAuth Client ID Metadata Document format
|
|
- ✅ Required fields: client_id, redirect_uris
|
|
- ✅ Recommended fields: client_name, client_uri
|
|
|
|
### OAuth 2.0 Standards
|
|
- ✅ RFC 7591: OAuth 2.0 Dynamic Client Registration
|
|
- ✅ Client metadata format
|
|
- ✅ Public client (no client secret)
|
|
|
|
### HTTP Standards
|
|
- ✅ RFC 7231: HTTP/1.1 Semantics (cache headers)
|
|
- ✅ RFC 8259: JSON format
|
|
- ✅ IANA Well-Known URIs registry
|
|
|
|
### Project Standards
|
|
- ✅ Minimal code principle
|
|
- ✅ Standards-first design
|
|
- ✅ No unnecessary dependencies
|
|
- ✅ Progressive enhancement (server-side)
|
|
|
|
## References
|
|
|
|
### Specifications
|
|
- [IndieAuth Specification](https://indieauth.spec.indieweb.org/)
|
|
- [OAuth Client ID Metadata Document](https://www.ietf.org/archive/id/draft-parecki-oauth-client-id-metadata-document-00.html)
|
|
- [RFC 7591 - OAuth 2.0 Dynamic Client Registration](https://www.rfc-editor.org/rfc/rfc7591.html)
|
|
- [RFC 3986 - URI Generic Syntax](https://www.rfc-editor.org/rfc/rfc3986)
|
|
|
|
### IndieWeb Resources
|
|
- [IndieAuth on IndieWeb](https://indieweb.org/IndieAuth)
|
|
- [Client Identifier Discovery](https://indieweb.org/client_id)
|
|
- [IndieLogin.com Documentation](https://indielogin.com/api)
|
|
|
|
### Internal Documents
|
|
- ADR-016: IndieAuth Client Discovery Mechanism (superseded)
|
|
- ADR-006: IndieAuth Client Identification Strategy (superseded)
|
|
- ADR-005: IndieLogin Authentication
|
|
- Root Cause Analysis: IndieAuth Client Discovery (docs/reports/)
|
|
|
|
## Related ADRs
|
|
|
|
- **Supersedes**: ADR-016 (h-app approach insufficient)
|
|
- **Supersedes**: ADR-006 (visibility issue but wrong approach)
|
|
- **Extends**: ADR-005 (adds missing client discovery to IndieLogin flow)
|
|
- **Related**: ADR-003 (frontend architecture - templates)
|
|
|
|
## Version Impact
|
|
|
|
**Issue Type**: Critical Bug (authentication completely broken in production)
|
|
**Version Change**: v0.6.1 → v0.6.2
|
|
**Semantic Versioning**: Patch increment (bug fix, no breaking changes)
|
|
**Changelog Category**: Fixed
|
|
|
|
## Notes for Implementation
|
|
|
|
### Developer Guidance
|
|
|
|
1. **Use Configuration Variables**: Never hardcode URLs, always use `current_app.config['SITE_URL']`
|
|
2. **Test JSON Structure**: Validate with `jq` before deploying
|
|
3. **Verify Exact Match**: client_id must EXACTLY match URL (string comparison)
|
|
4. **Cache Appropriately**: 24 hours is safe, metadata rarely changes
|
|
5. **Keep It Simple**: No complex logic, just dictionary serialization
|
|
|
|
### Common Pitfalls to Avoid
|
|
|
|
1. ❌ Hardcoding URLs instead of using config
|
|
2. ❌ Using string instead of array for redirect_uris
|
|
3. ❌ Missing client_id field (spec requirement)
|
|
4. ❌ client_id doesn't match document URL
|
|
5. ❌ Forgetting to add discovery link to HTML
|
|
6. ❌ Wrong content-type header
|
|
7. ❌ No cache headers (unnecessary server load)
|
|
|
|
### Debugging Tips
|
|
|
|
```bash
|
|
# Verify endpoint exists and returns JSON
|
|
curl -v https://starpunk.thesatelliteoflove.com/.well-known/oauth-authorization-server
|
|
|
|
# Pretty-print JSON response
|
|
curl -s https://starpunk.thesatelliteoflove.com/.well-known/oauth-authorization-server | jq .
|
|
|
|
# Check specific field
|
|
curl -s https://starpunk.thesatelliteoflove.com/.well-known/oauth-authorization-server | \
|
|
jq '.client_id'
|
|
|
|
# Verify cache headers
|
|
curl -I https://starpunk.thesatelliteoflove.com/.well-known/oauth-authorization-server
|
|
|
|
# Test from IndieLogin's perspective (check what they see)
|
|
curl -s -H "User-Agent: IndieLogin" \
|
|
https://starpunk.thesatelliteoflove.com/.well-known/oauth-authorization-server
|
|
```
|
|
|
|
---
|
|
|
|
**Decided**: 2025-11-19
|
|
**Author**: StarPunk Architect Agent
|
|
**Supersedes**: ADR-016, ADR-006
|
|
**Status**: Proposed (awaiting implementation and validation)
|