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
··· 47 47 - Lexicon definitions: `social.coves.community.comment.defs` and `getComments` 48 48 - Database query methods with Lemmy hot ranking algorithm 49 49 - Service layer with iterative loading strategy for nested replies 50 - - XRPC HTTP handler with optional authentication 50 + - XRPC HTTP handler with optional DPoP authentication 51 51 - Comprehensive integration test suite (11 test scenarios) 52 52 53 53 **What works:** ··· 55 55 - Nested replies up to configurable depth (default 10, max 100) 56 56 - Lemmy hot ranking: `log(greatest(2, score + 2)) / power(time_decay, 1.8)` 57 57 - Cursor-based pagination for stable scrolling 58 - - Optional authentication for viewer state (stubbed for Phase 2B) 58 + - Optional DPoP authentication for viewer state (stubbed for Phase 2B) 59 59 - Timeframe filtering for "top" sort (hour/day/week/month/year/all) 60 60 61 61 **Endpoints:** ··· 63 63 - Required: `post` (AT-URI) 64 64 - Optional: `sort` (hot/top/new), `depth` (0-100), `limit` (1-100), `cursor`, `timeframe` 65 65 - Returns: Array of `threadViewComment` with nested replies + post context 66 - - Supports Bearer token for authenticated requests (viewer state) 66 + - Supports DPoP-bound access token for authenticated requests (viewer state) 67 67 68 68 **Files created (9):** 69 69 1. `internal/atproto/lexicon/social/coves/community/comment/defs.json` - View definitions ··· 976 976 **8. Viewer Authentication Validation (Non-Issue - Architecture Working as Designed)** 977 977 - **Initial Concern:** ViewerDID field trusted without verification in service layer 978 978 - **Investigation:** Authentication IS properly validated at middleware layer 979 - - `OptionalAuth` middleware extracts and validates JWT Bearer tokens 979 + - `OptionalAuth` middleware extracts and validates DPoP-bound access tokens 980 980 - Uses PDS public keys (JWKS) for signature verification 981 - - Validates token expiration, DID format, issuer 981 + - Validates DPoP proof, token expiration, DID format, issuer 982 982 - Only injects verified DIDs into request context 983 983 - Handler extracts DID using `middleware.GetUserDID(r)` 984 984 - **Architecture:** Follows industry best practices (authentication at perimeter)
+7 -4
docs/FEED_SYSTEM_IMPLEMENTATION.md
··· 203 203 # Get personalized timeline (hot posts from subscriptions) 204 204 curl -X GET \ 205 205 'http://localhost:8081/xrpc/social.coves.feed.getTimeline?sort=hot&limit=15' \ 206 - -H 'Authorization: Bearer eyJhbGc...' 206 + -H 'Authorization: DPoP eyJhbGc...' \ 207 + -H 'DPoP: eyJhbGc...' 207 208 208 209 # Get top posts from last week 209 210 curl -X GET \ 210 211 'http://localhost:8081/xrpc/social.coves.feed.getTimeline?sort=top&timeframe=week&limit=20' \ 211 - -H 'Authorization: Bearer eyJhbGc...' 212 + -H 'Authorization: DPoP eyJhbGc...' \ 213 + -H 'DPoP: eyJhbGc...' 212 214 213 215 # Get newest posts with pagination 214 216 curl -X GET \ 215 217 'http://localhost:8081/xrpc/social.coves.feed.getTimeline?sort=new&limit=10&cursor=<cursor>' \ 216 - -H 'Authorization: Bearer eyJhbGc...' 218 + -H 'Authorization: DPoP eyJhbGc...' \ 219 + -H 'DPoP: eyJhbGc...' 217 220 ``` 218 221 219 222 **Response:** ··· 313 316 - โœ… Context timeout support 314 317 315 318 ### Authentication (Timeline) 316 - - โœ… JWT Bearer token required 319 + - โœ… DPoP-bound access token required 317 320 - โœ… DID extracted from auth context 318 321 - โœ… Validates token signature (when AUTH_SKIP_VERIFY=false) 319 322 - โœ… Returns 401 on auth failure
+3 -3
docs/PRD_OAUTH.md
··· 10 10 - โœ… Auth middleware protecting community endpoints 11 11 - โœ… Handlers updated to use `GetUserDID(r)` 12 12 - โœ… Comprehensive middleware auth tests (11 test cases) 13 - - โœ… E2E tests updated to use Bearer tokens 13 + - โœ… E2E tests updated to use DPoP-bound tokens 14 14 - โœ… Security logging with IP, method, path, issuer 15 15 - โœ… Scope validation (atproto required) 16 16 - โœ… Issuer HTTPS validation ··· 163 163 Authorization: DPoP eyJhbGciOiJFUzI1NiIsInR5cCI6ImF0K2p3dCIsImtpZCI6ImRpZDpwbGM6YWxpY2UjYXRwcm90by1wZHMifQ... 164 164 ``` 165 165 166 - Format: `DPoP <access_token>` 166 + Format: `DPoP <access_token>` (note: uses "DPoP" scheme, not "Bearer") 167 167 168 168 The access token is a JWT containing: 169 169 ```json ··· 753 753 - [x] All community endpoints reject requests without valid JWT structure 754 754 - [x] Integration tests pass with mock tokens (11/11 middleware tests passing) 755 755 - [x] Zero security regressions from X-User-DID (JWT validation is strictly better) 756 - - [x] E2E tests updated to use proper Bearer token authentication 756 + - [x] E2E tests updated to use proper DPoP token authentication 757 757 - [x] Build succeeds without compilation errors 758 758 759 759 ### Phase 2 (Beta) - โœ… READY FOR TESTING
+3 -1
docs/aggregators/SETUP_GUIDE.md
··· 256 256 257 257 **Request**: 258 258 ```bash 259 + # Note: This calls the PDS directly, so it uses Bearer authorization (not DPoP) 259 260 curl -X POST https://bsky.social/xrpc/com.atproto.repo.createRecord \ 260 261 -H "Authorization: Bearer YOUR_ACCESS_TOKEN" \ 261 262 -H "Content-Type: application/json" \ ··· 354 355 355 356 **Request**: 356 357 ```bash 358 + # Note: This calls the Coves API, so it uses DPoP authorization 357 359 curl -X POST https://api.coves.social/xrpc/social.coves.community.post.create \ 358 - -H "Authorization: Bearer YOUR_ACCESS_TOKEN" \ 360 + -H "Authorization: DPoP YOUR_ACCESS_TOKEN" \ 359 361 -H "Content-Type: application/json" \ 360 362 -d '{ 361 363 "communityDid": "did:plc:community123...",
+8 -2
docs/federation-prd.md
··· 263 263 req, _ := http.NewRequestWithContext(ctx, "POST", endpoint, bytes.NewBuffer(jsonData)) 264 264 265 265 // Use service auth token instead of community credentials 266 + // NOTE: Auth scheme depends on target PDS implementation: 267 + // - Standard atproto service auth uses "Bearer" scheme 268 + // - Our AppView uses "DPoP" scheme when DPoP-bound tokens are required 269 + // For server-to-server with standard PDS, use Bearer; adjust based on target. 266 270 req.Header.Set("Authorization", "Bearer "+serviceAuthToken) 267 271 req.Header.Set("Content-Type", "application/json") 268 272 ··· 726 730 **Request to Remote PDS:** 727 731 ```http 728 732 POST https://covesinstance.com/xrpc/com.atproto.server.getServiceAuth 729 - Authorization: Bearer {coves-social-instance-jwt} 733 + Authorization: DPoP {coves-social-instance-jwt} 734 + DPoP: {coves-social-dpop-proof} 730 735 Content-Type: application/json 731 736 732 737 { ··· 749 754 **Using Token to Create Post:** 750 755 ```http 751 756 POST https://covesinstance.com/xrpc/com.atproto.repo.createRecord 752 - Authorization: Bearer {service-auth-token} 757 + Authorization: DPoP {service-auth-token} 758 + DPoP: {service-auth-dpop-proof} 753 759 Content-Type: application/json 754 760 755 761 {
+12 -8
internal/atproto/auth/README.md
··· 1 1 # atProto OAuth Authentication 2 2 3 - This package implements third-party OAuth authentication for Coves, validating JWT Bearer tokens from mobile apps and other atProto clients. 3 + This package implements third-party OAuth authentication for Coves, validating DPoP-bound access tokens from mobile apps and other atProto clients. 4 4 5 5 ## Architecture 6 6 ··· 17 17 ``` 18 18 Client Request 19 19 โ†“ 20 - Authorization: Bearer <jwt> 20 + Authorization: DPoP <access_token> 21 + DPoP: <proof-jwt> 21 22 โ†“ 22 23 Auth Middleware 23 24 โ†“ 24 - Extract JWT โ†’ Parse Claims โ†’ Verify Signature (via JWKS) 25 + Extract JWT โ†’ Parse Claims โ†’ Verify Signature (via JWKS) โ†’ Verify DPoP Proof 25 26 โ†“ 26 27 Inject DID into Context โ†’ Call Handler 27 28 ``` ··· 71 72 72 73 ```bash 73 74 curl -X POST https://coves.social/xrpc/social.coves.community.create \ 74 - -H "Authorization: Bearer eyJhbGc..." \ 75 + -H "Authorization: DPoP eyJhbGc..." \ 76 + -H "DPoP: eyJhbGc..." \ 75 77 -H "Content-Type: application/json" \ 76 78 -d '{"name":"Gaming","hostedByDid":"did:plc:..."}' 77 79 ``` ··· 141 143 โ”‚ โ”‚ โ”‚ (Coves) โ”‚ 142 144 โ””โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”˜ โ””โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”˜ 143 145 โ”‚ โ”‚ 144 - โ”‚ 1. Authorization: Bearer <token> โ”‚ 146 + โ”‚ 1. Authorization: DPoP <token> โ”‚ 145 147 โ”‚ DPoP: <proof-jwt> โ”‚ 146 148 โ”‚โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€>โ”‚ 147 149 โ”‚ โ”‚ ··· 276 278 # Create a test JWT (use jwt.io or a tool) 277 279 export AUTH_SKIP_VERIFY=true 278 280 curl -X POST http://localhost:8081/xrpc/social.coves.community.create \ 279 - -H "Authorization: Bearer <test-jwt>" \ 281 + -H "Authorization: DPoP <test-jwt>" \ 282 + -H "DPoP: <test-dpop-proof>" \ 280 283 -d '{"name":"Test","hostedByDid":"did:plc:test"}' 281 284 ``` 282 285 ··· 285 288 # Use a real JWT from a PDS 286 289 export AUTH_SKIP_VERIFY=false 287 290 curl -X POST http://localhost:8081/xrpc/social.coves.community.create \ 288 - -H "Authorization: Bearer <real-jwt>" \ 291 + -H "Authorization: DPoP <real-jwt>" \ 292 + -H "DPoP: <real-dpop-proof>" \ 289 293 -d '{"name":"Test","hostedByDid":"did:plc:test"}' 290 294 ``` 291 295 ··· 311 315 312 316 ### Common Issues 313 317 314 - 1. **Missing Authorization header** โ†’ Add `Authorization: Bearer <token>` 318 + 1. **Missing Authorization header** โ†’ Add `Authorization: DPoP <token>` and `DPoP: <proof>` 315 319 2. **Token expired** โ†’ Get a new token from PDS 316 320 3. **Invalid signature** โ†’ Ensure token is from a valid PDS 317 321 4. **JWKS fetch fails** โ†’ Check PDS availability and network connectivity
+1 -1
scripts/aggregator-setup/README.md
··· 175 175 176 176 ```bash 177 177 curl -X POST https://api.coves.social/xrpc/social.coves.community.post.create \ 178 - -H "Authorization: Bearer $AGGREGATOR_ACCESS_JWT" \ 178 + -H "Authorization: DPoP $AGGREGATOR_ACCESS_JWT" \ 179 179 -H "Content-Type: application/json" \ 180 180 -d '{ 181 181 "communityDid": "did:plc:...",