docs: Address Micropub design issues and clarify V1 scope
- Create ADR-029 for IndieAuth/Micropub integration strategy - Address all critical issues from developer review: - Add missing 'me' parameter to token endpoint - Clarify PKCE as optional extension - Define token security migration strategy - Add authorization_codes table schema - Define property mapping rules - Clarify two authentication flows - Simplify V1 scope per user decision: - Remove update/delete operations from V1 - Focus on create-only functionality - Reduce timeline from 8-10 to 6-8 days - Update project plan with post-V1 roadmap: - Phase 11: Update/delete operations (V1.1) - Phase 12: Media endpoint (V1.2) - Phase 13: Advanced IndieWeb features (V2.0) - Phase 14: Enhanced features (V2.0+) - Create token security migration documentation - Update ADR-028 for consistency with simplified scope BREAKING CHANGE: Token migration will invalidate all existing tokens for security
This commit is contained in:
@@ -53,14 +53,15 @@ We will implement a **minimal but complete Micropub server** for V1, focusing on
|
||||
- Delegate to existing `notes.py` CRUD functions
|
||||
- Proper error handling and status codes
|
||||
|
||||
3. **V1 Feature Scope**
|
||||
3. **V1 Feature Scope** (Simplified per user decision)
|
||||
- ✅ Create posts (form-encoded and JSON)
|
||||
- ✅ Query endpoints (config, source)
|
||||
- ✅ Bearer token authentication
|
||||
- ✅ Scope-based authorization
|
||||
- ❌ Media endpoint (deferred)
|
||||
- ❌ Update/delete operations (deferred)
|
||||
- ❌ Syndication (deferred)
|
||||
- ✅ Scope-based authorization (create only)
|
||||
- ❌ Media endpoint (post-V1)
|
||||
- ❌ Update operations (post-V1)
|
||||
- ❌ Delete operations (post-V1)
|
||||
- ❌ Syndication (post-V1)
|
||||
|
||||
### Technology Choices
|
||||
|
||||
@@ -139,12 +140,14 @@ We will implement a **minimal but complete Micropub server** for V1, focusing on
|
||||
- Create post functionality
|
||||
- Error response formatting
|
||||
|
||||
### Phase 3: Queries & Polish (Days 8-10)
|
||||
### Phase 3: Queries & Polish (Days 6-8)
|
||||
- Config and source query endpoints
|
||||
- Authorization endpoint scope handling
|
||||
- Authorization endpoint with admin session check
|
||||
- Discovery headers and links
|
||||
- Client testing and documentation
|
||||
|
||||
**Note**: Timeline reduced from 8-10 days to 6-8 days due to V1 scope simplification (no update/delete)
|
||||
|
||||
## Alternatives Considered
|
||||
|
||||
### Alternative 1: Full Micropub Implementation
|
||||
|
||||
537
docs/decisions/ADR-029-micropub-indieauth-integration.md
Normal file
537
docs/decisions/ADR-029-micropub-indieauth-integration.md
Normal file
@@ -0,0 +1,537 @@
|
||||
# ADR-029: Micropub IndieAuth Integration Strategy
|
||||
|
||||
## Status
|
||||
Accepted
|
||||
|
||||
## Context
|
||||
|
||||
The developer review of our Micropub design (ADR-028) revealed critical issues and questions about how IndieAuth and Micropub integrate. This ADR addresses all architectural decisions needed to proceed with implementation.
|
||||
|
||||
### Critical Issues Identified
|
||||
|
||||
1. **Token endpoint missing required `me` parameter** in the IndieAuth spec
|
||||
2. **PKCE confusion** - it's not part of IndieAuth spec, but StarPunk uses it with IndieLogin.com
|
||||
3. **Database security issue** - tokens stored in plain text
|
||||
4. **Missing `authorization_codes` table** for token exchange
|
||||
5. **Property mapping rules** undefined for Micropub to StarPunk conversion
|
||||
6. **Authorization endpoint location** unclear
|
||||
7. **Two authentication flows** need clarification
|
||||
|
||||
### V1 Scope Decision
|
||||
|
||||
The user has agreed to **simplify V1** by:
|
||||
- ✅ Omitting update operations from V1
|
||||
- ✅ Omitting delete operations from V1
|
||||
- ✅ Focusing on create-only for V1 release
|
||||
- Post-V1 features will be tracked separately
|
||||
|
||||
## Decision
|
||||
|
||||
We will implement a **hybrid IndieAuth architecture** that clearly separates admin authentication from Micropub authorization.
|
||||
|
||||
### Architectural Decisions
|
||||
|
||||
#### 1. Token Endpoint `me` Parameter (RESOLVED)
|
||||
|
||||
**Issue**: IndieAuth spec requires `me` parameter in token exchange, but our design missed it.
|
||||
|
||||
**Decision**: Add `me` parameter validation to token endpoint.
|
||||
|
||||
**Implementation**:
|
||||
```python
|
||||
# Token exchange request MUST include:
|
||||
POST /auth/token
|
||||
grant_type=authorization_code
|
||||
code={code}
|
||||
client_id={client_url}
|
||||
redirect_uri={redirect_url}
|
||||
me={user_profile_url} # REQUIRED by IndieAuth spec
|
||||
```
|
||||
|
||||
**Validation**:
|
||||
- Verify `me` matches the value stored with the authorization code
|
||||
- Return error if mismatch (prevents code hijacking)
|
||||
|
||||
#### 2. PKCE Strategy (RESOLVED)
|
||||
|
||||
**Issue**: PKCE is not part of IndieAuth spec, but StarPunk uses it with IndieLogin.com.
|
||||
|
||||
**Decision**: Make PKCE **optional but recommended**.
|
||||
|
||||
**Implementation**:
|
||||
- Check for `code_challenge` in authorization request
|
||||
- If present, require `code_verifier` in token exchange
|
||||
- If absent, proceed without PKCE (spec-compliant)
|
||||
- Document as security enhancement beyond spec
|
||||
|
||||
**Rationale**:
|
||||
- IndieLogin.com supports PKCE as an extension
|
||||
- Other IndieAuth providers may not support it
|
||||
- Making it optional ensures broader compatibility
|
||||
|
||||
#### 3. Token Storage Security (RESOLVED)
|
||||
|
||||
**Issue**: Current `tokens` table stores tokens in plain text (major security vulnerability).
|
||||
|
||||
**Decision**: Implement **immediate migration** to hashed token storage.
|
||||
|
||||
**Migration Strategy**:
|
||||
```sql
|
||||
-- Step 1: Create new secure tokens table
|
||||
CREATE TABLE tokens_secure (
|
||||
id INTEGER PRIMARY KEY AUTOINCREMENT,
|
||||
token_hash TEXT UNIQUE NOT NULL, -- SHA256 hash
|
||||
me TEXT NOT NULL,
|
||||
client_id TEXT,
|
||||
scope TEXT DEFAULT 'create',
|
||||
created_at TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP,
|
||||
expires_at TIMESTAMP NOT NULL,
|
||||
last_used_at TIMESTAMP,
|
||||
revoked_at TIMESTAMP
|
||||
);
|
||||
|
||||
-- Step 2: Invalidate all existing tokens (security breach recovery)
|
||||
-- Since we can't hash plain text tokens retroactively, all must be revoked
|
||||
DROP TABLE IF EXISTS tokens;
|
||||
|
||||
-- Step 3: Rename secure table
|
||||
ALTER TABLE tokens_secure RENAME TO tokens;
|
||||
|
||||
-- Step 4: Create indexes
|
||||
CREATE INDEX idx_tokens_hash ON tokens(token_hash);
|
||||
CREATE INDEX idx_tokens_me ON tokens(me);
|
||||
CREATE INDEX idx_tokens_expires ON tokens(expires_at);
|
||||
```
|
||||
|
||||
**Security Notice**: All existing tokens will be invalidated. Users must re-authenticate.
|
||||
|
||||
#### 4. Authorization Codes Table (RESOLVED)
|
||||
|
||||
**Issue**: Design references `authorization_codes` table that doesn't exist.
|
||||
|
||||
**Decision**: Create the table as part of Micropub implementation.
|
||||
|
||||
**Schema**:
|
||||
```sql
|
||||
CREATE TABLE authorization_codes (
|
||||
code TEXT PRIMARY KEY,
|
||||
code_hash TEXT UNIQUE NOT NULL, -- SHA256 hash for security
|
||||
me TEXT NOT NULL,
|
||||
client_id TEXT NOT NULL,
|
||||
redirect_uri TEXT NOT NULL,
|
||||
scope TEXT DEFAULT 'create',
|
||||
code_challenge TEXT, -- Optional PKCE
|
||||
code_challenge_method TEXT, -- S256 if PKCE used
|
||||
created_at TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP,
|
||||
expires_at TIMESTAMP NOT NULL,
|
||||
used_at TIMESTAMP -- Prevent replay attacks
|
||||
);
|
||||
|
||||
CREATE INDEX idx_auth_codes_hash ON authorization_codes(code_hash);
|
||||
CREATE INDEX idx_auth_codes_expires ON authorization_codes(expires_at);
|
||||
```
|
||||
|
||||
#### 5. Property Mapping Rules (RESOLVED)
|
||||
|
||||
**Issue**: Functions like `extract_title()` and `extract_content()` are undefined.
|
||||
|
||||
**Decision**: Define explicit mapping rules for V1.
|
||||
|
||||
**Micropub → StarPunk Mapping**:
|
||||
```python
|
||||
# Content mapping (required)
|
||||
content = properties.get('content', [''])[0] # First content value
|
||||
if not content:
|
||||
return error_response("invalid_request", "Content is required")
|
||||
|
||||
# Title mapping (optional)
|
||||
# Option 1: Use 'name' property if provided
|
||||
title = properties.get('name', [''])[0]
|
||||
# Option 2: If no name, extract from content (first line up to 50 chars)
|
||||
if not title and content:
|
||||
first_line = content.split('\n')[0]
|
||||
title = first_line[:50] + ('...' if len(first_line) > 50 else '')
|
||||
|
||||
# Tags mapping
|
||||
tags = properties.get('category', []) # All category values become tags
|
||||
|
||||
# Published date (respect if provided, otherwise use current time)
|
||||
published = properties.get('published', [''])[0]
|
||||
if published:
|
||||
# Parse ISO 8601 date
|
||||
created_at = parse_iso8601(published)
|
||||
else:
|
||||
created_at = datetime.now()
|
||||
|
||||
# Slug generation
|
||||
mp_slug = properties.get('mp-slug', [''])[0]
|
||||
if mp_slug:
|
||||
slug = slugify(mp_slug)
|
||||
else:
|
||||
slug = generate_slug(title or content[:30])
|
||||
```
|
||||
|
||||
### Q1: Authorization Endpoint Location (RESOLVED)
|
||||
|
||||
**Issue**: Design mentions `/auth/authorization` but it doesn't exist.
|
||||
|
||||
**Decision**: Create **NEW** `/auth/authorization` endpoint for Micropub clients.
|
||||
|
||||
**Rationale**:
|
||||
- Keep admin login (`/auth/login`) separate from Micropub authorization
|
||||
- Clear separation of concerns
|
||||
- Follows IndieAuth spec naming conventions
|
||||
|
||||
**Implementation**:
|
||||
```python
|
||||
@bp.route("/auth/authorization", methods=["GET", "POST"])
|
||||
def authorization_endpoint():
|
||||
"""
|
||||
IndieAuth authorization endpoint for Micropub clients
|
||||
|
||||
GET: Display authorization form
|
||||
POST: Process authorization and redirect with code
|
||||
"""
|
||||
if request.method == "GET":
|
||||
# Parse IndieAuth parameters
|
||||
response_type = request.args.get('response_type')
|
||||
client_id = request.args.get('client_id')
|
||||
redirect_uri = request.args.get('redirect_uri')
|
||||
state = request.args.get('state')
|
||||
scope = request.args.get('scope', 'create')
|
||||
me = request.args.get('me')
|
||||
code_challenge = request.args.get('code_challenge')
|
||||
|
||||
# Validate parameters
|
||||
if response_type != 'code':
|
||||
return error_response("unsupported_response_type")
|
||||
|
||||
# Check if user is logged in (via admin session)
|
||||
if not verify_admin_session():
|
||||
# Redirect to login, then back here
|
||||
session['pending_auth'] = request.url
|
||||
return redirect(url_for('auth.login_form'))
|
||||
|
||||
# Display authorization form
|
||||
return render_template('auth/authorize.html',
|
||||
client_id=client_id,
|
||||
scope=scope,
|
||||
redirect_uri=redirect_uri)
|
||||
|
||||
else: # POST
|
||||
# User approved/denied authorization
|
||||
# Generate authorization code
|
||||
# Store in authorization_codes table
|
||||
# Redirect to client with code
|
||||
```
|
||||
|
||||
### Q2: Two Authentication Flows Integration (RESOLVED)
|
||||
|
||||
**Decision**: Maintain **two separate flows** with clear boundaries.
|
||||
|
||||
**Flow 1: Admin Login** (Existing)
|
||||
- Purpose: Admin access to StarPunk interface
|
||||
- Path: `/auth/login` → IndieLogin.com → `/auth/callback`
|
||||
- Result: Session cookie for admin panel
|
||||
- No changes needed
|
||||
|
||||
**Flow 2: Micropub Authorization** (New)
|
||||
- Purpose: Micropub client authorization
|
||||
- Path: `/auth/authorization` → `/auth/token`
|
||||
- Result: Bearer token for API access
|
||||
|
||||
**Integration Point**: The authorization endpoint checks for admin session:
|
||||
```python
|
||||
def authorization_endpoint():
|
||||
# Check if admin is logged in
|
||||
if not has_admin_session():
|
||||
# Store authorization request
|
||||
# Redirect to admin login
|
||||
# After login, return to authorization
|
||||
return redirect_to_login_with_return()
|
||||
|
||||
# Admin is logged in, show authorization form
|
||||
return show_authorization_form()
|
||||
```
|
||||
|
||||
**Key Design Choice**: We act as our **own authorization server** for Micropub, not delegating to IndieLogin.com for this flow. This is because:
|
||||
1. IndieLogin.com doesn't issue access tokens
|
||||
2. We need to control scopes and token lifetime
|
||||
3. We already have admin authentication to verify the user
|
||||
|
||||
### Q3: Scope Validation Rules (RESOLVED)
|
||||
|
||||
**Issue**: What happens when client requests no scopes?
|
||||
|
||||
**Decision**: Implement **Option C** - Allow empty scope during authorization, reject at token endpoint.
|
||||
|
||||
**Rationale**: This matches the IndieAuth spec requirement exactly.
|
||||
|
||||
**Implementation**:
|
||||
```python
|
||||
def handle_authorization():
|
||||
scope = request.args.get('scope', '')
|
||||
|
||||
# Store whatever scope was requested (even empty)
|
||||
authorization_code = create_authorization_code(
|
||||
scope=scope, # Can be empty string
|
||||
# ... other parameters
|
||||
)
|
||||
|
||||
def handle_token_exchange():
|
||||
auth_code = get_authorization_code(code)
|
||||
|
||||
# IndieAuth spec: MUST NOT issue token if no scope
|
||||
if not auth_code.scope:
|
||||
return error_response("invalid_scope",
|
||||
"Authorization code was issued without scope")
|
||||
|
||||
# Issue token with the authorized scope
|
||||
token = create_access_token(scope=auth_code.scope)
|
||||
```
|
||||
|
||||
### Q4: V1 Scope - Update/Delete Operations (RESOLVED)
|
||||
|
||||
**Decision**: Remove update/delete from V1 completely.
|
||||
|
||||
**Changes Required**:
|
||||
1. Remove `handle_update()` and `handle_delete()` from design doc
|
||||
2. Remove update/delete from supported scopes in V1
|
||||
3. Return "invalid_request" if action=update or action=delete
|
||||
4. Document in project plan for post-V1
|
||||
|
||||
**V1 Supported Actions**:
|
||||
- ✅ action=create (or no action - default)
|
||||
- ❌ action=update → error response
|
||||
- ❌ action=delete → error response
|
||||
|
||||
### Q5: Token Storage Security Fix (RESOLVED)
|
||||
|
||||
**Decision**: Fix the security issue as part of Micropub implementation.
|
||||
|
||||
**Implementation Plan**:
|
||||
1. Create migration to new secure schema
|
||||
2. Hash all new tokens before storage
|
||||
3. Document that existing tokens will be invalidated
|
||||
4. Add security notice to changelog
|
||||
|
||||
## Implementation Architecture
|
||||
|
||||
### Complete Authorization Flow
|
||||
|
||||
```
|
||||
┌─────────────────────────────────────────────────────────┐
|
||||
│ Micropub Client │
|
||||
└────────────────────┬────────────────────────────────────┘
|
||||
│
|
||||
│ 1. GET /auth/authorization?
|
||||
│ response_type=code&
|
||||
│ client_id=https://app.example&
|
||||
│ redirect_uri=...&
|
||||
│ state=...&
|
||||
│ scope=create&
|
||||
│ me=https://user.example
|
||||
▼
|
||||
┌─────────────────────────────────────────────────────────┐
|
||||
│ StarPunk Authorization Endpoint │
|
||||
│ /auth/authorization │
|
||||
├─────────────────────────────────────────────────────────┤
|
||||
│ if not admin_logged_in: │
|
||||
│ redirect_to_login() │
|
||||
│ else: │
|
||||
│ show_authorization_form() │
|
||||
└────────────────────┬────────────────────────────────────┘
|
||||
│
|
||||
│ 2. User approves
|
||||
│ POST /auth/authorization
|
||||
│
|
||||
│ 3. Redirect with code
|
||||
│ https://app.example/callback?
|
||||
│ code=xxx&state=yyy
|
||||
▼
|
||||
┌─────────────────────────────────────────────────────────┐
|
||||
│ Micropub Client │
|
||||
└────────────────────┬────────────────────────────────────┘
|
||||
│
|
||||
│ 4. POST /auth/token
|
||||
│ grant_type=authorization_code&
|
||||
│ code=xxx&
|
||||
│ client_id=https://app.example&
|
||||
│ redirect_uri=...&
|
||||
│ me=https://user.example&
|
||||
│ code_verifier=... (if PKCE)
|
||||
▼
|
||||
┌─────────────────────────────────────────────────────────┐
|
||||
│ StarPunk Token Endpoint │
|
||||
│ /auth/token │
|
||||
├─────────────────────────────────────────────────────────┤
|
||||
│ 1. Verify authorization code │
|
||||
│ 2. Check code not used │
|
||||
│ 3. Verify client_id matches │
|
||||
│ 4. Verify redirect_uri matches │
|
||||
│ 5. Verify me matches │
|
||||
│ 6. Verify PKCE if present │
|
||||
│ 7. Check scope not empty │
|
||||
│ 8. Generate access token │
|
||||
│ 9. Store hashed token │
|
||||
│ 10. Return token response │
|
||||
└────────────────────┬────────────────────────────────────┘
|
||||
│
|
||||
│ 5. Response:
|
||||
│ {
|
||||
│ "access_token": "xxx",
|
||||
│ "token_type": "Bearer",
|
||||
│ "scope": "create",
|
||||
│ "me": "https://user.example"
|
||||
│ }
|
||||
▼
|
||||
┌─────────────────────────────────────────────────────────┐
|
||||
│ Micropub Client │
|
||||
└────────────────────┬────────────────────────────────────┘
|
||||
│
|
||||
│ 6. POST /micropub
|
||||
│ Authorization: Bearer xxx
|
||||
│ h=entry&content=Hello
|
||||
▼
|
||||
┌─────────────────────────────────────────────────────────┐
|
||||
│ StarPunk Micropub Endpoint │
|
||||
│ /micropub │
|
||||
├─────────────────────────────────────────────────────────┤
|
||||
│ 1. Extract bearer token │
|
||||
│ 2. Hash token and lookup │
|
||||
│ 3. Verify not expired │
|
||||
│ 4. Check scope includes "create" │
|
||||
│ 5. Parse Micropub properties │
|
||||
│ 6. Create note via notes.py │
|
||||
│ 7. Return 201 with Location header │
|
||||
└─────────────────────────────────────────────────────────┘
|
||||
```
|
||||
|
||||
## Consequences
|
||||
|
||||
### Positive
|
||||
- ✅ All spec compliance issues resolved
|
||||
- ✅ Clear separation between admin auth and Micropub auth
|
||||
- ✅ Security vulnerability in token storage fixed
|
||||
- ✅ Simplified V1 scope (create-only)
|
||||
- ✅ PKCE optional for compatibility
|
||||
- ✅ Clear property mapping rules
|
||||
|
||||
### Negative
|
||||
- ⚠️ Existing tokens will be invalidated (security fix)
|
||||
- ⚠️ More complex than initially designed
|
||||
- ⚠️ Two authorization flows to maintain
|
||||
|
||||
### Neutral
|
||||
- We become our own authorization server (for Micropub only)
|
||||
- Admin must be logged in to authorize Micropub clients
|
||||
- Update/delete deferred to post-V1
|
||||
|
||||
## Migration Requirements
|
||||
|
||||
### Database Migration Script
|
||||
```sql
|
||||
-- Migration: Fix token security and add authorization codes
|
||||
-- Version: 0.10.0
|
||||
|
||||
-- 1. Create secure tokens table
|
||||
CREATE TABLE tokens_new (
|
||||
id INTEGER PRIMARY KEY AUTOINCREMENT,
|
||||
token_hash TEXT UNIQUE NOT NULL,
|
||||
me TEXT NOT NULL,
|
||||
client_id TEXT,
|
||||
scope TEXT DEFAULT 'create',
|
||||
created_at TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP,
|
||||
expires_at TIMESTAMP NOT NULL,
|
||||
last_used_at TIMESTAMP,
|
||||
revoked_at TIMESTAMP
|
||||
);
|
||||
|
||||
-- 2. Drop insecure table (invalidates all tokens)
|
||||
DROP TABLE IF EXISTS tokens;
|
||||
|
||||
-- 3. Rename to final name
|
||||
ALTER TABLE tokens_new RENAME TO tokens;
|
||||
|
||||
-- 4. Create authorization codes table
|
||||
CREATE TABLE authorization_codes (
|
||||
id INTEGER PRIMARY KEY AUTOINCREMENT,
|
||||
code_hash TEXT UNIQUE NOT NULL,
|
||||
me TEXT NOT NULL,
|
||||
client_id TEXT NOT NULL,
|
||||
redirect_uri TEXT NOT NULL,
|
||||
scope TEXT,
|
||||
state TEXT,
|
||||
code_challenge TEXT,
|
||||
code_challenge_method TEXT,
|
||||
created_at TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP,
|
||||
expires_at TIMESTAMP NOT NULL,
|
||||
used_at TIMESTAMP
|
||||
);
|
||||
|
||||
-- 5. Create indexes
|
||||
CREATE INDEX idx_tokens_hash ON tokens(token_hash);
|
||||
CREATE INDEX idx_tokens_expires ON tokens(expires_at);
|
||||
CREATE INDEX idx_auth_codes_hash ON authorization_codes(code_hash);
|
||||
CREATE INDEX idx_auth_codes_expires ON authorization_codes(expires_at);
|
||||
|
||||
-- 6. Clean up expired auth state
|
||||
DELETE FROM auth_state WHERE expires_at < datetime('now');
|
||||
```
|
||||
|
||||
## Implementation Checklist
|
||||
|
||||
### Phase 1: Security & Database
|
||||
- [ ] Create database migration script
|
||||
- [ ] Implement token hashing functions
|
||||
- [ ] Add authorization_codes table
|
||||
- [ ] Update database.py schema
|
||||
|
||||
### Phase 2: Authorization Endpoint
|
||||
- [ ] Create `/auth/authorization` route
|
||||
- [ ] Implement authorization form template
|
||||
- [ ] Add scope approval UI
|
||||
- [ ] Generate and store authorization codes
|
||||
|
||||
### Phase 3: Token Endpoint
|
||||
- [ ] Create `/auth/token` route
|
||||
- [ ] Implement code exchange logic
|
||||
- [ ] Add `me` parameter validation
|
||||
- [ ] Optional PKCE verification
|
||||
- [ ] Generate and store hashed tokens
|
||||
|
||||
### Phase 4: Micropub Endpoint (Create Only)
|
||||
- [ ] Create `/micropub` route
|
||||
- [ ] Bearer token extraction
|
||||
- [ ] Token verification (hash lookup)
|
||||
- [ ] Property normalization
|
||||
- [ ] Content/title/tags mapping
|
||||
- [ ] Note creation via notes.py
|
||||
- [ ] Location header response
|
||||
|
||||
### Phase 5: Testing & Documentation
|
||||
- [ ] Test with Indigenous app
|
||||
- [ ] Test with Quill
|
||||
- [ ] Update API documentation
|
||||
- [ ] Security audit
|
||||
- [ ] Performance testing
|
||||
|
||||
## References
|
||||
|
||||
- [IndieAuth Spec - Token Endpoint](https://indieauth.spec.indieweb.org/#token-endpoint)
|
||||
- [IndieAuth Spec - Authorization Code](https://indieauth.spec.indieweb.org/#authorization-code)
|
||||
- [Micropub Spec - Authentication](https://www.w3.org/TR/micropub/#authentication)
|
||||
- [OAuth 2.0 Security Best Practices](https://datatracker.ietf.org/doc/html/draft-ietf-oauth-security-topics)
|
||||
|
||||
## Related ADRs
|
||||
|
||||
- ADR-021: IndieAuth Provider Strategy (understanding flows)
|
||||
- ADR-028: Micropub Implementation Strategy (original design)
|
||||
- ADR-005: IndieLogin Authentication (admin auth flow)
|
||||
|
||||
---
|
||||
|
||||
**Date**: 2024-11-24
|
||||
**Author**: StarPunk Architecture Team
|
||||
**Status**: Accepted
|
||||
**Version Impact**: Requires 0.10.0 (breaking change - token invalidation)
|
||||
Reference in New Issue
Block a user