A community based topic aggregation platform built on atproto

docs: update authentication documentation for DPoP scheme

Update documentation to reflect the transition from Bearer tokens
to DPoP-bound tokens for client authentication:

- federation-prd.md: Update auth examples to use DPoP scheme
- Add note about Bearer vs DPoP for server-to-server auth
- Update request examples with DPoP header

- COMMENT_SYSTEM_IMPLEMENTATION.md: Update auth references
- "Bearer token" โ†’ "DPoP-bound access token"
- Document DPoP proof validation in OptionalAuth

- FEED_SYSTEM_IMPLEMENTATION.md: Update curl examples
- Add DPoP header alongside Authorization header
- Update auth requirement description

- PRD_OAUTH.md, aggregators/SETUP_GUIDE.md, auth/README.md:
- Minor terminology updates for consistency

๐Ÿค– Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude <noreply@anthropic.com>

Changed files
+39 -24
docs
internal
atproto
auth
scripts
aggregator-setup
+5 -5
docs/COMMENT_SYSTEM_IMPLEMENTATION.md
···
- Lexicon definitions: `social.coves.community.comment.defs` and `getComments`
- Database query methods with Lemmy hot ranking algorithm
- Service layer with iterative loading strategy for nested replies
-
- XRPC HTTP handler with optional authentication
+
- XRPC HTTP handler with optional DPoP authentication
- Comprehensive integration test suite (11 test scenarios)
**What works:**
···
- Nested replies up to configurable depth (default 10, max 100)
- Lemmy hot ranking: `log(greatest(2, score + 2)) / power(time_decay, 1.8)`
- Cursor-based pagination for stable scrolling
-
- Optional authentication for viewer state (stubbed for Phase 2B)
+
- Optional DPoP authentication for viewer state (stubbed for Phase 2B)
- Timeframe filtering for "top" sort (hour/day/week/month/year/all)
**Endpoints:**
···
- Required: `post` (AT-URI)
- Optional: `sort` (hot/top/new), `depth` (0-100), `limit` (1-100), `cursor`, `timeframe`
- Returns: Array of `threadViewComment` with nested replies + post context
-
- Supports Bearer token for authenticated requests (viewer state)
+
- Supports DPoP-bound access token for authenticated requests (viewer state)
**Files created (9):**
1. `internal/atproto/lexicon/social/coves/community/comment/defs.json` - View definitions
···
**8. Viewer Authentication Validation (Non-Issue - Architecture Working as Designed)**
- **Initial Concern:** ViewerDID field trusted without verification in service layer
- **Investigation:** Authentication IS properly validated at middleware layer
-
- `OptionalAuth` middleware extracts and validates JWT Bearer tokens
+
- `OptionalAuth` middleware extracts and validates DPoP-bound access tokens
- Uses PDS public keys (JWKS) for signature verification
-
- Validates token expiration, DID format, issuer
+
- Validates DPoP proof, token expiration, DID format, issuer
- Only injects verified DIDs into request context
- Handler extracts DID using `middleware.GetUserDID(r)`
- **Architecture:** Follows industry best practices (authentication at perimeter)
+7 -4
docs/FEED_SYSTEM_IMPLEMENTATION.md
···
# Get personalized timeline (hot posts from subscriptions)
curl -X GET \
'http://localhost:8081/xrpc/social.coves.feed.getTimeline?sort=hot&limit=15' \
-
-H 'Authorization: Bearer eyJhbGc...'
+
-H 'Authorization: DPoP eyJhbGc...' \
+
-H 'DPoP: eyJhbGc...'
# Get top posts from last week
curl -X GET \
'http://localhost:8081/xrpc/social.coves.feed.getTimeline?sort=top&timeframe=week&limit=20' \
-
-H 'Authorization: Bearer eyJhbGc...'
+
-H 'Authorization: DPoP eyJhbGc...' \
+
-H 'DPoP: eyJhbGc...'
# Get newest posts with pagination
curl -X GET \
'http://localhost:8081/xrpc/social.coves.feed.getTimeline?sort=new&limit=10&cursor=<cursor>' \
-
-H 'Authorization: Bearer eyJhbGc...'
+
-H 'Authorization: DPoP eyJhbGc...' \
+
-H 'DPoP: eyJhbGc...'
```
**Response:**
···
- โœ… Context timeout support
### Authentication (Timeline)
-
- โœ… JWT Bearer token required
+
- โœ… DPoP-bound access token required
- โœ… DID extracted from auth context
- โœ… Validates token signature (when AUTH_SKIP_VERIFY=false)
- โœ… Returns 401 on auth failure
+3 -3
docs/PRD_OAUTH.md
···
- โœ… Auth middleware protecting community endpoints
- โœ… Handlers updated to use `GetUserDID(r)`
- โœ… Comprehensive middleware auth tests (11 test cases)
-
- โœ… E2E tests updated to use Bearer tokens
+
- โœ… E2E tests updated to use DPoP-bound tokens
- โœ… Security logging with IP, method, path, issuer
- โœ… Scope validation (atproto required)
- โœ… Issuer HTTPS validation
···
Authorization: DPoP eyJhbGciOiJFUzI1NiIsInR5cCI6ImF0K2p3dCIsImtpZCI6ImRpZDpwbGM6YWxpY2UjYXRwcm90by1wZHMifQ...
```
-
Format: `DPoP <access_token>`
+
Format: `DPoP <access_token>` (note: uses "DPoP" scheme, not "Bearer")
The access token is a JWT containing:
```json
···
- [x] All community endpoints reject requests without valid JWT structure
- [x] Integration tests pass with mock tokens (11/11 middleware tests passing)
- [x] Zero security regressions from X-User-DID (JWT validation is strictly better)
-
- [x] E2E tests updated to use proper Bearer token authentication
+
- [x] E2E tests updated to use proper DPoP token authentication
- [x] Build succeeds without compilation errors
### Phase 2 (Beta) - โœ… READY FOR TESTING
+3 -1
docs/aggregators/SETUP_GUIDE.md
···
**Request**:
```bash
+
# Note: This calls the PDS directly, so it uses Bearer authorization (not DPoP)
curl -X POST https://bsky.social/xrpc/com.atproto.repo.createRecord \
-H "Authorization: Bearer YOUR_ACCESS_TOKEN" \
-H "Content-Type: application/json" \
···
**Request**:
```bash
+
# Note: This calls the Coves API, so it uses DPoP authorization
curl -X POST https://api.coves.social/xrpc/social.coves.community.post.create \
-
-H "Authorization: Bearer YOUR_ACCESS_TOKEN" \
+
-H "Authorization: DPoP YOUR_ACCESS_TOKEN" \
-H "Content-Type: application/json" \
-d '{
"communityDid": "did:plc:community123...",
+8 -2
docs/federation-prd.md
···
req, _ := http.NewRequestWithContext(ctx, "POST", endpoint, bytes.NewBuffer(jsonData))
// Use service auth token instead of community credentials
+
// NOTE: Auth scheme depends on target PDS implementation:
+
// - Standard atproto service auth uses "Bearer" scheme
+
// - Our AppView uses "DPoP" scheme when DPoP-bound tokens are required
+
// For server-to-server with standard PDS, use Bearer; adjust based on target.
req.Header.Set("Authorization", "Bearer "+serviceAuthToken)
req.Header.Set("Content-Type", "application/json")
···
**Request to Remote PDS:**
```http
POST https://covesinstance.com/xrpc/com.atproto.server.getServiceAuth
-
Authorization: Bearer {coves-social-instance-jwt}
+
Authorization: DPoP {coves-social-instance-jwt}
+
DPoP: {coves-social-dpop-proof}
Content-Type: application/json
{
···
**Using Token to Create Post:**
```http
POST https://covesinstance.com/xrpc/com.atproto.repo.createRecord
-
Authorization: Bearer {service-auth-token}
+
Authorization: DPoP {service-auth-token}
+
DPoP: {service-auth-dpop-proof}
Content-Type: application/json
{
+12 -8
internal/atproto/auth/README.md
···
# atProto OAuth Authentication
-
This package implements third-party OAuth authentication for Coves, validating JWT Bearer tokens from mobile apps and other atProto clients.
+
This package implements third-party OAuth authentication for Coves, validating DPoP-bound access tokens from mobile apps and other atProto clients.
## Architecture
···
```
Client Request
โ†“
-
Authorization: Bearer <jwt>
+
Authorization: DPoP <access_token>
+
DPoP: <proof-jwt>
โ†“
Auth Middleware
โ†“
-
Extract JWT โ†’ Parse Claims โ†’ Verify Signature (via JWKS)
+
Extract JWT โ†’ Parse Claims โ†’ Verify Signature (via JWKS) โ†’ Verify DPoP Proof
โ†“
Inject DID into Context โ†’ Call Handler
```
···
```bash
curl -X POST https://coves.social/xrpc/social.coves.community.create \
-
-H "Authorization: Bearer eyJhbGc..." \
+
-H "Authorization: DPoP eyJhbGc..." \
+
-H "DPoP: eyJhbGc..." \
-H "Content-Type: application/json" \
-d '{"name":"Gaming","hostedByDid":"did:plc:..."}'
```
···
โ”‚ โ”‚ โ”‚ (Coves) โ”‚
โ””โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”˜ โ””โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”˜
โ”‚ โ”‚
-
โ”‚ 1. Authorization: Bearer <token> โ”‚
+
โ”‚ 1. Authorization: DPoP <token> โ”‚
โ”‚ DPoP: <proof-jwt> โ”‚
โ”‚โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€>โ”‚
โ”‚ โ”‚
···
# Create a test JWT (use jwt.io or a tool)
export AUTH_SKIP_VERIFY=true
curl -X POST http://localhost:8081/xrpc/social.coves.community.create \
-
-H "Authorization: Bearer <test-jwt>" \
+
-H "Authorization: DPoP <test-jwt>" \
+
-H "DPoP: <test-dpop-proof>" \
-d '{"name":"Test","hostedByDid":"did:plc:test"}'
```
···
# Use a real JWT from a PDS
export AUTH_SKIP_VERIFY=false
curl -X POST http://localhost:8081/xrpc/social.coves.community.create \
-
-H "Authorization: Bearer <real-jwt>" \
+
-H "Authorization: DPoP <real-jwt>" \
+
-H "DPoP: <real-dpop-proof>" \
-d '{"name":"Test","hostedByDid":"did:plc:test"}'
```
···
### Common Issues
-
1. **Missing Authorization header** โ†’ Add `Authorization: Bearer <token>`
+
1. **Missing Authorization header** โ†’ Add `Authorization: DPoP <token>` and `DPoP: <proof>`
2. **Token expired** โ†’ Get a new token from PDS
3. **Invalid signature** โ†’ Ensure token is from a valid PDS
4. **JWKS fetch fails** โ†’ Check PDS availability and network connectivity
+1 -1
scripts/aggregator-setup/README.md
···
```bash
curl -X POST https://api.coves.social/xrpc/social.coves.community.post.create \
-
-H "Authorization: Bearer $AGGREGATOR_ACCESS_JWT" \
+
-H "Authorization: DPoP $AGGREGATOR_ACCESS_JWT" \
-H "Content-Type: application/json" \
-d '{
"communityDid": "did:plc:...",