A community based topic aggregation platform built on atproto
1# atProto OAuth Authentication 2 3This package implements third-party OAuth authentication for Coves, validating JWT Bearer tokens from mobile apps and other atProto clients. 4 5## Architecture 6 7This is **third-party authentication** (validating incoming requests), not first-party authentication (logging users into Coves web frontend). 8 9### Components 10 111. **JWT Parser** (`jwt.go`) - Parses and validates JWT tokens 122. **JWKS Fetcher** (`jwks_fetcher.go`) - Fetches and caches public keys from PDS authorization servers 133. **Auth Middleware** (`internal/api/middleware/auth.go`) - HTTP middleware that protects endpoints 14 15### Flow 16 17``` 18Client Request 19 20Authorization: Bearer <jwt> 21 22Auth Middleware 23 24Extract JWT → Parse Claims → Verify Signature (via JWKS) 25 26Inject DID into Context → Call Handler 27``` 28 29## Usage 30 31### Phase 1: Parse-Only Mode (Testing) 32 33Set `AUTH_SKIP_VERIFY=true` to only parse JWTs without signature verification: 34 35```bash 36export AUTH_SKIP_VERIFY=true 37``` 38 39This is useful for: 40- Initial integration testing 41- Testing with mock tokens 42- Debugging JWT structure 43 44### Phase 2: Full Verification (Production) 45 46Set `AUTH_SKIP_VERIFY=false` (or unset) to enable full JWT signature verification: 47 48```bash 49export AUTH_SKIP_VERIFY=false 50# or just unset it 51``` 52 53This is **required for production** and validates: 54- JWT signature using PDS public key 55- Token expiration 56- Required claims (sub, iss) 57- DID format 58 59## Protected Endpoints 60 61The following endpoints require authentication: 62 63- `POST /xrpc/social.coves.community.create` 64- `POST /xrpc/social.coves.community.update` 65- `POST /xrpc/social.coves.community.subscribe` 66- `POST /xrpc/social.coves.community.unsubscribe` 67 68### Making Authenticated Requests 69 70Include the JWT in the `Authorization` header: 71 72```bash 73curl -X POST https://coves.social/xrpc/social.coves.community.create \ 74 -H "Authorization: Bearer eyJhbGc..." \ 75 -H "Content-Type: application/json" \ 76 -d '{"name":"Gaming","hostedByDid":"did:plc:..."}' 77``` 78 79### Getting User DID in Handlers 80 81The middleware injects the authenticated user's DID into the request context: 82 83```go 84import "Coves/internal/api/middleware" 85 86func (h *Handler) HandleCreate(w http.ResponseWriter, r *http.Request) { 87 // Extract authenticated user DID 88 userDID := middleware.GetUserDID(r) 89 if userDID == "" { 90 // Not authenticated (should never happen with RequireAuth middleware) 91 http.Error(w, "Unauthorized", http.StatusUnauthorized) 92 return 93 } 94 95 // Use userDID for authorization checks 96 // ... 97} 98``` 99 100## Key Caching 101 102Public keys are fetched from PDS authorization servers and cached for 1 hour. The cache is automatically cleaned up hourly to remove expired entries. 103 104### JWKS Discovery Flow 105 1061. Extract `iss` claim from JWT (e.g., `https://pds.example.com`) 1072. Fetch `https://pds.example.com/.well-known/oauth-authorization-server` 1083. Extract `jwks_uri` from metadata 1094. Fetch JWKS from `jwks_uri` 1105. Find matching key by `kid` from JWT header 1116. Cache the JWKS for 1 hour 112 113## Security Considerations 114 115### ✅ Implemented 116 117- JWT signature verification with PDS public keys 118- Token expiration validation 119- DID format validation 120- Required claims validation (sub, iss) 121- Key caching with TTL 122- Secure error messages (no internal details leaked) 123 124### ⚠️ Not Yet Implemented 125 126- DPoP validation (for replay attack prevention) 127- Scope validation (checking `scope` claim) 128- Audience validation (checking `aud` claim) 129- Rate limiting per DID 130- Token revocation checking 131 132## Testing 133 134Run the test suite: 135 136```bash 137go test ./internal/atproto/auth/... -v 138``` 139 140### Manual Testing 141 1421. **Phase 1 (Parse Only)**: 143 ```bash 144 # Create a test JWT (use jwt.io or a tool) 145 export AUTH_SKIP_VERIFY=true 146 curl -X POST http://localhost:8081/xrpc/social.coves.community.create \ 147 -H "Authorization: Bearer <test-jwt>" \ 148 -d '{"name":"Test","hostedByDid":"did:plc:test"}' 149 ``` 150 1512. **Phase 2 (Full Verification)**: 152 ```bash 153 # Use a real JWT from a PDS 154 export AUTH_SKIP_VERIFY=false 155 curl -X POST http://localhost:8081/xrpc/social.coves.community.create \ 156 -H "Authorization: Bearer <real-jwt>" \ 157 -d '{"name":"Test","hostedByDid":"did:plc:test"}' 158 ``` 159 160## Error Responses 161 162### 401 Unauthorized 163 164Missing or invalid token: 165 166```json 167{ 168 "error": "AuthenticationRequired", 169 "message": "Missing Authorization header" 170} 171``` 172 173```json 174{ 175 "error": "AuthenticationRequired", 176 "message": "Invalid or expired token" 177} 178``` 179 180### Common Issues 181 1821. **Missing Authorization header** → Add `Authorization: Bearer <token>` 1832. **Token expired** → Get a new token from PDS 1843. **Invalid signature** → Ensure token is from a valid PDS 1854. **JWKS fetch fails** → Check PDS availability and network connectivity 186 187## Future Enhancements 188 189- [ ] DPoP proof validation 190- [ ] Scope-based authorization 191- [ ] Audience claim validation 192- [ ] Token revocation support 193- [ ] Rate limiting per DID 194- [ ] Metrics and monitoring