- Updated 42 references from indieauth.spec.indieweb.org to www.w3.org/TR/indieauth - Ensures consistency across all documentation - Points to the authoritative W3C specification - No functional changes, documentation update only Generated with Claude Code Co-Authored-By: Claude <noreply@anthropic.com>
542 lines
20 KiB
Markdown
542 lines
20 KiB
Markdown
# ADR-021: IndieAuth Provider Strategy
|
|
|
|
## Status
|
|
Accepted
|
|
|
|
## Context
|
|
|
|
StarPunk currently uses IndieLogin.com for authentication (ADR-005), but there is a critical misunderstanding about how IndieAuth works that needs to be addressed.
|
|
|
|
### The Problem
|
|
|
|
The user reported that IndieLogin.com requires manual client_id registration, making it unsuitable for self-hosted software where each installation has a different domain. This concern is based on a fundamental misunderstanding of how IndieAuth differs from traditional OAuth2.
|
|
|
|
### How IndieAuth Actually Works
|
|
|
|
Unlike traditional OAuth2 providers (GitHub, Google, etc.), **IndieAuth does not require pre-registration**:
|
|
|
|
1. **DNS-Based Client Identification**: IndieAuth uses DNS as a replacement for client registration. A client application identifies itself using its own URL (e.g., `https://starpunk.example.com`), which serves as a unique identifier.
|
|
|
|
2. **No Secrets Required**: All clients are public clients. There are no client secrets to manage or register.
|
|
|
|
3. **Dynamic Redirect URI Verification**: Instead of pre-registered redirect URIs, applications publish their valid redirect URLs at their client_id URL, which authorization servers can discover.
|
|
|
|
4. **Client Metadata Discovery**: Authorization servers can optionally fetch the client_id URL to display application information (name, logo) to users during authorization.
|
|
|
|
### StarPunk's Authentication Architecture
|
|
|
|
It is critical to understand that StarPunk has **two distinct authentication flows**:
|
|
|
|
#### Flow 1: Admin Authentication (Current Misunderstanding)
|
|
**Purpose**: Authenticate the StarPunk admin user to access the admin interface
|
|
**Current Implementation**: Uses IndieLogin.com as described in ADR-005
|
|
**How it works**:
|
|
1. Admin visits `/admin/login`
|
|
2. StarPunk redirects to IndieLogin.com with its own URL as `client_id`
|
|
3. IndieLogin.com verifies the admin's identity
|
|
4. Admin receives session cookie to access StarPunk admin
|
|
|
|
**Registration Required?** NO - IndieAuth never requires registration
|
|
|
|
#### Flow 2: Micropub Client Authorization (The Real Architecture)
|
|
**Purpose**: Allow external Micropub clients to publish to StarPunk
|
|
**How it works**:
|
|
1. User configures their personal website (e.g., `https://alice.com`) with links to StarPunk's Micropub endpoint
|
|
2. User opens Micropub client (Quill, Indigenous, etc.)
|
|
3. Client discovers authorization/token endpoints from `https://alice.com` (NOT from StarPunk)
|
|
4. Client gets access token from the discovered authorization server
|
|
5. Client uses token to POST to StarPunk's Micropub endpoint
|
|
6. StarPunk verifies the token
|
|
|
|
**Who Provides Authorization?** The USER's chosen authorization server, not StarPunk
|
|
|
|
### The Real Question
|
|
|
|
StarPunk faces two architectural decisions:
|
|
|
|
1. **Admin Authentication**: How should StarPunk administrators authenticate to the admin interface?
|
|
2. **User Authorization**: Should StarPunk provide authorization/token endpoints for its users, or should users bring their own?
|
|
|
|
## Research Findings
|
|
|
|
### Alternative IndieAuth Services
|
|
|
|
**IndieLogin.com** (Current)
|
|
- Actively maintained by Aaron Parecki (IndieAuth spec editor)
|
|
- Supports multiple auth methods: RelMeAuth, email, PGP, BlueSky OAuth (added 2025)
|
|
- **No registration required** - this was the key misunderstanding
|
|
- Free, community service
|
|
- High availability
|
|
|
|
**tokens.indieauth.com**
|
|
- Provides token endpoint functionality
|
|
- Separate from authorization endpoint
|
|
- Also maintained by IndieWeb community
|
|
- Also requires no registration
|
|
|
|
**Other Services**
|
|
- No other widely-used public IndieAuth providers found
|
|
- Most implementations are self-hosted (see below)
|
|
|
|
### Self-Hosted IndieAuth Implementations
|
|
|
|
**Taproot/IndieAuth** (PHP)
|
|
- Complexity: Moderate (7/10)
|
|
- Full-featured: Authorization + token endpoints
|
|
- PSR-7 compatible, well-tested (100% coverage)
|
|
- Lightweight dependencies (Guzzle, mf2)
|
|
- Production-ready since v0.1.0
|
|
|
|
**Selfauth** (PHP)
|
|
- Complexity: Low (3/10)
|
|
- **Limitation**: Authorization endpoint ONLY (no token endpoint)
|
|
- Cannot be used for Micropub (requires token endpoint)
|
|
- Suitable only for simple authentication use cases
|
|
|
|
**hacdias/indieauth** (Go)
|
|
- Complexity: Moderate (6/10)
|
|
- Provides both server and client libraries
|
|
- Modern Go implementation
|
|
- Used in production by author
|
|
|
|
**Custom Implementation** (Python)
|
|
- Complexity: High (8/10)
|
|
- Must implement IndieAuth spec 1.1
|
|
- Required endpoints:
|
|
- Authorization endpoint (authentication + code generation)
|
|
- Token endpoint (token issuance + verification)
|
|
- Metadata endpoint (server discovery)
|
|
- Introspection endpoint (token verification)
|
|
- Must support:
|
|
- PKCE (required by spec)
|
|
- Client metadata discovery
|
|
- Profile URL validation
|
|
- Scope-based permissions
|
|
- Token revocation
|
|
- Estimated effort: 40-60 hours for full implementation
|
|
- Ongoing maintenance burden for security updates
|
|
|
|
## Decision
|
|
|
|
**Recommendation: Continue Using IndieLogin.com with Clarified Architecture**
|
|
|
|
StarPunk should:
|
|
|
|
1. **For Admin Authentication**: Continue using IndieLogin.com (no changes needed)
|
|
- No registration required
|
|
- Works out of the box for self-hosted installations
|
|
- Each StarPunk instance uses its own domain as client_id
|
|
- Zero maintenance burden
|
|
|
|
2. **For Micropub Authorization**: Document that users must provide their own authorization server
|
|
- User configures their personal domain with IndieAuth endpoints
|
|
- User can choose:
|
|
- IndieLogin.com (easiest)
|
|
- Self-hosted IndieAuth server (advanced)
|
|
- Any other IndieAuth-compliant service
|
|
- StarPunk only verifies tokens, doesn't issue them
|
|
|
|
3. **For V2 Consideration**: Optionally provide built-in authorization server
|
|
- Would allow StarPunk to be a complete standalone solution
|
|
- Users could use StarPunk's domain as their identity
|
|
- Requires implementing full IndieAuth server (40-60 hours)
|
|
- Only pursue if there is strong user demand
|
|
|
|
## Rationale
|
|
|
|
### Why Continue with IndieLogin.com
|
|
|
|
**Simplicity Score: 10/10**
|
|
- Zero configuration required
|
|
- No registration process
|
|
- Works immediately for any domain
|
|
- Battle-tested by IndieWeb community
|
|
- The original concern (manual registration) does not exist
|
|
|
|
**Fitness Score: 10/10**
|
|
- Perfect for single-user CMS
|
|
- Aligns with IndieWeb principles
|
|
- User controls their identity
|
|
- No lock-in (user can switch authorization servers)
|
|
|
|
**Maintenance Score: 10/10**
|
|
- Externally maintained
|
|
- Security updates handled by community
|
|
- No code to maintain in StarPunk
|
|
- Proven reliability and uptime
|
|
|
|
**Standards Compliance: Pass**
|
|
- Full IndieAuth spec compliance
|
|
- OAuth 2.0 compatible
|
|
- Supports modern extensions (PKCE, client metadata)
|
|
|
|
### Why Not Self-Host (for V1)
|
|
|
|
**Complexity vs Benefit**
|
|
- Self-hosting adds 40-60 hours of development
|
|
- Ongoing security maintenance burden
|
|
- Solves a problem that doesn't exist (no registration required)
|
|
- Violates "every line of code must justify its existence"
|
|
|
|
**User Perspective**
|
|
- Users already need a domain for IndieWeb
|
|
- Most users will use IndieLogin.com or similar service
|
|
- Advanced users can self-host their own IndieAuth server
|
|
- StarPunk doesn't need to solve this problem
|
|
|
|
**Alternative Philosophy**
|
|
- StarPunk is a Micropub SERVER, not an authorization server
|
|
- Separation of concerns: publishing vs identity
|
|
- Users should control their own identity infrastructure
|
|
- StarPunk focuses on doing one thing well: publishing notes
|
|
|
|
## Architectural Clarification
|
|
|
|
### Current Architecture (Correct Understanding)
|
|
|
|
```
|
|
┌─────────────────────────────────────────────────────────────┐
|
|
│ Flow 1: Admin Authentication │
|
|
│ │
|
|
│ StarPunk Admin │
|
|
│ ↓ │
|
|
│ StarPunk (/admin/login) │
|
|
│ ↓ (redirect with client_id=https://starpunk.example) │
|
|
│ IndieLogin.com (verifies admin identity) │
|
|
│ ↓ (returns verified "me" URL) │
|
|
│ StarPunk (creates session) │
|
|
└─────────────────────────────────────────────────────────────┘
|
|
|
|
┌─────────────────────────────────────────────────────────────┐
|
|
│ Flow 2: Micropub Publishing │
|
|
│ │
|
|
│ User's Website (https://alice.com) │
|
|
│ Links to: │
|
|
│ - authorization_endpoint (IndieLogin or self-hosted) │
|
|
│ - token_endpoint (tokens.indieauth.com or self-hosted) │
|
|
│ - micropub endpoint (StarPunk) │
|
|
│ ↓ │
|
|
│ Micropub Client (Quill, Indigenous) │
|
|
│ ↓ (discovers endpoints from alice.com) │
|
|
│ Authorization Server (user's choice, NOT StarPunk) │
|
|
│ ↓ (issues access token) │
|
|
│ Micropub Client │
|
|
│ ↓ (POST with Bearer token) │
|
|
│ StarPunk Micropub Endpoint │
|
|
│ ↓ (verifies token with authorization server) │
|
|
│ StarPunk (creates note) │
|
|
└─────────────────────────────────────────────────────────────┘
|
|
```
|
|
|
|
### What StarPunk Implements
|
|
|
|
**Currently Implemented** (ADR-005):
|
|
- Session-based admin authentication via IndieLogin.com
|
|
- CSRF protection (state tokens)
|
|
- Session management
|
|
- Admin route protection
|
|
|
|
**Must Be Implemented** (for Micropub):
|
|
- Token verification endpoint (query user's token endpoint)
|
|
- Bearer token extraction from Authorization header
|
|
- Scope verification (check token has "create" permission)
|
|
- Token storage/caching (optional, for performance)
|
|
|
|
**Does NOT Implement** (users provide these):
|
|
- Authorization endpoint (users use IndieLogin.com or self-hosted)
|
|
- Token endpoint (users use tokens.indieauth.com or self-hosted)
|
|
- User identity management (users own their domains)
|
|
|
|
## Implementation Outline
|
|
|
|
### No Changes Needed for Admin Auth
|
|
The current IndieLogin.com integration (ADR-005) is correct and requires no changes. Each self-hosted StarPunk installation uses its own domain as `client_id` without any registration.
|
|
|
|
### Required for Micropub Support
|
|
|
|
#### 1. Token Verification
|
|
```python
|
|
def verify_micropub_token(bearer_token, expected_me):
|
|
"""
|
|
Verify access token by querying the token endpoint
|
|
|
|
Args:
|
|
bearer_token: Token from Authorization header
|
|
expected_me: Expected user identity (from StarPunk config)
|
|
|
|
Returns:
|
|
dict: Token info (me, client_id, scope) if valid
|
|
None: If token is invalid
|
|
"""
|
|
# Discover token endpoint from expected_me domain
|
|
token_endpoint = discover_token_endpoint(expected_me)
|
|
|
|
# Verify token
|
|
response = httpx.get(
|
|
token_endpoint,
|
|
headers={'Authorization': f'Bearer {bearer_token}'},
|
|
params={'token': bearer_token}
|
|
)
|
|
|
|
if response.status_code != 200:
|
|
return None
|
|
|
|
data = response.json()
|
|
|
|
# Verify token is for expected user
|
|
if data.get('me') != expected_me:
|
|
return None
|
|
|
|
# Verify token has required scope
|
|
scope = data.get('scope', '')
|
|
if 'create' not in scope:
|
|
return None
|
|
|
|
return data
|
|
```
|
|
|
|
#### 2. Endpoint Discovery
|
|
```python
|
|
def discover_token_endpoint(me_url):
|
|
"""
|
|
Discover token endpoint from user's profile URL
|
|
|
|
Checks for:
|
|
1. indieauth-metadata endpoint
|
|
2. Fallback to direct token_endpoint link
|
|
"""
|
|
response = httpx.get(me_url)
|
|
|
|
# Check HTTP Link header
|
|
link_header = response.headers.get('Link', '')
|
|
# Parse link header for indieauth-metadata
|
|
|
|
# Check HTML <link> tags
|
|
# Parse HTML for <link rel="indieauth-metadata">
|
|
|
|
# Fetch metadata endpoint
|
|
# Return token_endpoint URL
|
|
```
|
|
|
|
#### 3. Micropub Endpoint Protection
|
|
```python
|
|
@app.route('/api/micropub', methods=['POST'])
|
|
def micropub_endpoint():
|
|
# Extract bearer token
|
|
auth_header = request.headers.get('Authorization', '')
|
|
if not auth_header.startswith('Bearer '):
|
|
return {'error': 'unauthorized'}, 401
|
|
|
|
bearer_token = auth_header[7:] # Remove "Bearer "
|
|
|
|
# Verify token
|
|
token_info = verify_micropub_token(bearer_token, ADMIN_ME)
|
|
if not token_info:
|
|
return {'error': 'forbidden'}, 403
|
|
|
|
# Process Micropub request
|
|
# Create note
|
|
# Return 201 with Location header
|
|
```
|
|
|
|
### Documentation Updates
|
|
|
|
#### For Users (Setup Guide)
|
|
```markdown
|
|
# Setting Up Your IndieWeb Identity
|
|
|
|
To publish to StarPunk via Micropub clients:
|
|
|
|
1. **Add Links to Your Website**
|
|
Add these to your personal website's <head>:
|
|
```html
|
|
<link rel="authorization_endpoint" href="https://indielogin.com/auth">
|
|
<link rel="token_endpoint" href="https://tokens.indieauth.com/token">
|
|
<link rel="micropub" href="https://your-starpunk.example.com/api/micropub">
|
|
```
|
|
|
|
2. **Configure StarPunk**
|
|
Set your website URL in StarPunk configuration:
|
|
```
|
|
ADMIN_ME=https://your-website.com
|
|
```
|
|
|
|
3. **Use a Micropub Client**
|
|
- Quill: https://quill.p3k.io
|
|
- Indigenous (mobile app)
|
|
- Or any Micropub-compatible client
|
|
|
|
4. **Advanced: Self-Host Authorization**
|
|
Instead of IndieLogin.com, you can run your own IndieAuth server.
|
|
See: https://indieweb.org/IndieAuth#Software
|
|
```
|
|
|
|
#### For Developers (Architecture Docs)
|
|
Update `/home/phil/Projects/starpunk/docs/architecture/overview.md` to clarify the two authentication flows and explain that StarPunk is a Micropub server, not an authorization server.
|
|
|
|
## Consequences
|
|
|
|
### Positive
|
|
- **No development needed**: Current architecture is correct
|
|
- **No registration required**: Works for self-hosted installations out of the box
|
|
- **User control**: Users choose their own authorization provider
|
|
- **Standards compliant**: Proper separation of Micropub server and authorization server
|
|
- **Simple**: StarPunk focuses on publishing, not identity management
|
|
- **Flexible**: Users can switch authorization providers without affecting StarPunk
|
|
|
|
### Negative
|
|
- **User education required**: Must explain that they need to configure their domain
|
|
- **Not standalone**: StarPunk cannot function completely independently (requires external auth)
|
|
- **Dependency**: Relies on external services (mitigated: user chooses service)
|
|
|
|
### Neutral
|
|
- **Architectural purity**: Follows IndieWeb principle of separation of concerns
|
|
- **Complexity distribution**: Moves authorization complexity to where it belongs (identity provider)
|
|
|
|
## V2 Considerations
|
|
|
|
If there is user demand for a more integrated solution, V2 could add:
|
|
|
|
### Option A: Embedded IndieAuth Server
|
|
**Pros**:
|
|
- StarPunk becomes completely standalone
|
|
- Users can use StarPunk domain as their identity
|
|
- One-step setup for non-technical users
|
|
|
|
**Cons**:
|
|
- 40-60 hours development effort
|
|
- Ongoing security maintenance
|
|
- Adds complexity to codebase
|
|
- May violate simplicity principle
|
|
|
|
**Decision**: Only implement if users request it
|
|
|
|
### Option B: Hybrid Mode
|
|
**Pros**:
|
|
- Advanced users can use external auth (current behavior)
|
|
- Simple users can use built-in auth
|
|
- Best of both worlds
|
|
|
|
**Cons**:
|
|
- Even more complexity
|
|
- Two codepaths to maintain
|
|
- Configuration complexity
|
|
|
|
**Decision**: Defer until V2 user feedback
|
|
|
|
### Option C: StarPunk-Hosted Service
|
|
**Pros**:
|
|
- One StarPunk authorization server for all installations
|
|
- Users register their StarPunk instance once
|
|
- Simple for end users
|
|
|
|
**Cons**:
|
|
- Centralized service (not indie)
|
|
- Single point of failure
|
|
- Hosting/maintenance burden
|
|
- Violates IndieWeb principles
|
|
|
|
**Decision**: Rejected - not aligned with IndieWeb values
|
|
|
|
## Alternatives Considered
|
|
|
|
### Alternative 1: Self-Host IndieAuth (Taproot/PHP)
|
|
**Evaluation**:
|
|
- Complexity: Would require running PHP alongside Python
|
|
- Deployment: Two separate applications to manage
|
|
- Maintenance: Security updates for both Python and PHP
|
|
- Verdict: **Rejected** - adds unnecessary complexity
|
|
|
|
### Alternative 2: Port Taproot to Python
|
|
**Evaluation**:
|
|
- Effort: 40-60 hours development
|
|
- Maintenance: Full responsibility for security
|
|
- Value: Solves a non-existent problem (no registration needed)
|
|
- Verdict: **Rejected** - violates simplicity principle
|
|
|
|
### Alternative 3: Use OAuth2 Service (GitHub, Google)
|
|
**Evaluation**:
|
|
- Simplicity: Very simple to implement
|
|
- IndieWeb Compliance: **FAIL** - not IndieWeb compatible
|
|
- User Ownership: **FAIL** - users don't own their identity
|
|
- Verdict: **Rejected** - violates core requirements
|
|
|
|
### Alternative 4: Password Authentication
|
|
**Evaluation**:
|
|
- Simplicity: Moderate (password hashing, reset flows)
|
|
- IndieWeb Compliance: **FAIL** - not IndieWeb authentication
|
|
- Security: Must implement password best practices
|
|
- Verdict: **Rejected** - not aligned with IndieWeb principles
|
|
|
|
### Alternative 5: Use IndieAuth as Library (Client Side)
|
|
**Evaluation**:
|
|
- Would make StarPunk act as IndieAuth client to discover user's auth server
|
|
- Current architecture already does this for Micropub
|
|
- Admin interface uses simpler session-based auth
|
|
- Verdict: **Already implemented** for Micropub flow
|
|
|
|
## Migration Plan
|
|
|
|
### From Current Broken Understanding → Correct Understanding
|
|
|
|
**No Code Changes Required**
|
|
|
|
1. **Update Documentation**
|
|
- Clarify that no registration is needed
|
|
- Explain the two authentication flows
|
|
- Document Micropub setup for users
|
|
|
|
2. **Complete Micropub Implementation**
|
|
- Implement token verification
|
|
- Implement endpoint discovery
|
|
- Add Bearer token authentication
|
|
|
|
3. **User Education**
|
|
- Create setup guide explaining domain configuration
|
|
- Provide example HTML snippets
|
|
- Link to IndieWeb resources
|
|
|
|
### Timeline
|
|
- Documentation updates: 2 hours
|
|
- Micropub token verification: 8 hours
|
|
- Testing with real Micropub clients: 4 hours
|
|
- Total: ~14 hours
|
|
|
|
## References
|
|
|
|
### IndieAuth Specifications
|
|
- [IndieAuth Spec](https://www.w3.org/TR/indieauth/) - Official W3C specification
|
|
- [OAuth 2.0](https://oauth.net/2/) - Underlying OAuth 2.0 foundation
|
|
- [Client Identifier](https://www.oauth.com/oauth2-servers/indieauth/) - How client_id works in IndieAuth
|
|
|
|
### Services
|
|
- [IndieLogin.com](https://indielogin.com/) - Public IndieAuth service (no registration)
|
|
- [IndieLogin API Docs](https://indielogin.com/api) - Integration documentation
|
|
- [tokens.indieauth.com](https://tokens.indieauth.com/token) - Public token endpoint service
|
|
|
|
### Self-Hosted Implementations
|
|
- [Taproot/IndieAuth](https://github.com/Taproot/indieauth) - PHP implementation
|
|
- [hacdias/indieauth](https://github.com/hacdias/indieauth) - Go implementation
|
|
- [Selfauth](https://github.com/Inklings-io/selfauth) - Simple auth-only PHP
|
|
|
|
### IndieWeb Resources
|
|
- [IndieWeb Wiki: IndieAuth](https://indieweb.org/IndieAuth) - Community documentation
|
|
- [IndieWeb Wiki: Micropub](https://indieweb.org/Micropub) - Micropub overview
|
|
- [IndieWeb Wiki: authorization-endpoint](https://indieweb.org/authorization-endpoint) - Endpoint details
|
|
|
|
### Related ADRs
|
|
- [ADR-005: IndieLogin Authentication](/home/phil/Projects/starpunk/docs/decisions/ADR-005-indielogin-authentication.md) - Original auth decision
|
|
- [ADR-010: Authentication Module Design](/home/phil/Projects/starpunk/docs/decisions/ADR-010-authentication-module-design.md) - Auth module structure
|
|
|
|
### Community Examples
|
|
- [Aaron Parecki's IndieAuth Notes](https://aaronparecki.com/2025/10/08/4/cimd) - Client ID metadata adoption
|
|
- [Jamie Tanna's IndieAuth Server](https://www.jvt.me/posts/2020/12/09/personal-indieauth-server/) - Self-hosted implementation
|
|
- [Micropub Servers](https://indieweb.org/Micropub/Servers) - Examples of Micropub implementations
|
|
|
|
---
|
|
|
|
**Document Version**: 1.0
|
|
**Created**: 2025-11-19
|
|
**Author**: StarPunk Architecture Team (agent-architect)
|
|
**Status**: Accepted
|