A community based topic aggregation platform built on atproto

docs(aggregators): add API key setup script and update documentation

- Add 5-create-api-key.sh for generating aggregator API keys
- Update aggregator-setup README with step 5 documentation
- Clarify that domain verification (.well-known) is optional
- Document both PDS handle and custom domain options
- Update kagi-news README for API key authentication flow
- Replace old password-based auth references with API key auth

🤖 Generated with [Claude Code](https://claude.com/claude-code)

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

+245 -43
+24 -15
aggregators/kagi-news/README.md
··· 47 47 48 48 Before running the aggregator, you must register it with a Coves instance. This creates a DID for your aggregator and registers it with Coves. 49 49 50 + ### Handle Options 51 + 52 + You have two choices: 53 + 54 + 1. **PDS-assigned handle** (simpler): Use `my-aggregator.bsky.social`. No domain verification needed. 55 + 2. **Custom domain** (branded): Use `news.example.com`. Requires hosting a `.well-known/atproto-did` file. 56 + 50 57 ### Quick Setup (Automated) 51 58 52 59 The automated setup script handles the entire registration process: ··· 59 66 60 67 This will: 61 68 1. **Create a PDS account** for your aggregator (generates a DID) 62 - 2. **Generate `.well-known/atproto-did`** file for domain verification 63 - 3. **Pause for manual upload** - you'll upload the file to your web server 64 - 4. **Register with Coves** instance via XRPC 65 - 5. **Create service declaration** record (indexed by Jetstream) 69 + 2. **(Optional)** Generate `.well-known/atproto-did` file for custom domain handle 70 + 3. **(Optional)** Pause for manual upload if using custom domain 71 + 4. **Create service declaration** record (indexed by Jetstream) 72 + 5. **Generate an API key** for authentication (requires browser OAuth) 66 73 67 - **Manual step required:** During the process, you'll need to upload the `.well-known/atproto-did` file to your domain so it's accessible at `https://yourdomain.com/.well-known/atproto-did`. 74 + **Manual steps required:** 75 + - **(If using custom domain)** Upload `.well-known/atproto-did` to your domain 76 + - Complete OAuth login in browser to generate API key 68 77 69 - After completion, you'll have a `kagi-aggregator-config.env` file with: 70 - - Aggregator DID and credentials 71 - - Access/refresh JWTs 72 - - Service declaration URI 78 + After completion, you'll have: 79 + - `kagi-aggregator-config.env` - Full configuration with API key 80 + - `COVES_API_KEY` - Your authentication token for posting 73 81 74 - **Keep this file secure!** It contains your aggregator's credentials. 82 + **Keep the API key secure!** It cannot be retrieved after generation. 75 83 76 84 ### Manual Setup (Step-by-step) 77 85 ··· 81 89 # From the Coves project root 82 90 cd scripts/aggregator-setup 83 91 84 - # Follow the 4-step process 92 + # Follow the 5-step process 85 93 ./1-create-pds-account.sh 86 94 ./2-setup-wellknown.sh 87 95 ./3-register-with-coves.sh 88 96 ./4-create-service-declaration.sh 97 + ./5-create-api-key.sh 89 98 ``` 90 99 91 100 See [scripts/aggregator-setup/README.md](../../scripts/aggregator-setup/README.md) for detailed documentation on each step. ··· 96 105 2. **Domain Verification**: Proves you control your aggregator's domain 97 106 3. **Coves Registration**: Inserts your DID into the Coves instance's `users` table 98 107 4. **Service Declaration**: Creates a record that gets indexed into the `aggregators` table 99 - 5. **Ready for Authorization**: Community moderators can now authorize your aggregator 108 + 5. **API Key Generation**: Creates a secure API key for authentication 109 + 6. **Ready for Authorization**: Community moderators can now authorize your aggregator 100 110 101 111 Once registered and authorized by a community, your aggregator can post content. 102 112 ··· 128 138 ``` 129 139 130 140 4. Edit `config.yaml` to map RSS feeds to communities 131 - 5. Set environment variables in `.env` (aggregator DID and private key) 141 + 5. Set `COVES_API_KEY` in `.env` (from registration step 5) 132 142 133 143 ## Running Tests 134 144 ··· 189 199 190 200 The `docker-compose.yml` file supports these environment variables: 191 201 192 - - **`AGGREGATOR_HANDLE`** (required): Your aggregator's handle 193 - - **`AGGREGATOR_PASSWORD`** (required): Your aggregator's password 202 + - **`COVES_API_KEY`** (required): Your aggregator's API key (format: `ckapi_...`) 194 203 - **`COVES_API_URL`** (optional): Override Coves API endpoint (defaults to `https://api.coves.social`) 195 204 - **`RUN_ON_STARTUP`** (optional): Set to `true` to run immediately on container start (useful for testing) 196 205
+148
scripts/aggregator-setup/5-create-api-key.sh
··· 1 + #!/bin/bash 2 + # 3 + # Step 5: Create API Key for Aggregator 4 + # 5 + # This script guides you through generating an API key for your aggregator. 6 + # API keys are used for authentication instead of PDS JWTs. 7 + # 8 + # Prerequisites: 9 + # - Completed steps 1-4 (PDS account, .well-known, Coves registration, service declaration) 10 + # - Aggregator indexed by Coves (check: curl https://coves.social/xrpc/social.coves.aggregator.get?did=YOUR_DID) 11 + # 12 + # Usage: ./5-create-api-key.sh 13 + # 14 + 15 + set -e 16 + 17 + # Colors for output 18 + RED='\033[0;31m' 19 + GREEN='\033[0;32m' 20 + YELLOW='\033[1;33m' 21 + BLUE='\033[0;34m' 22 + NC='\033[0m' # No Color 23 + 24 + echo -e "${BLUE}╔════════════════════════════════════════════════════════════╗${NC}" 25 + echo -e "${BLUE}║ Coves Aggregator - Step 5: Create API Key ║${NC}" 26 + echo -e "${BLUE}╚════════════════════════════════════════════════════════════╝${NC}" 27 + echo 28 + 29 + # Load existing configuration 30 + CONFIG_FILE="aggregator-config.env" 31 + if [ -f "$CONFIG_FILE" ]; then 32 + echo -e "${GREEN}✓${NC} Loading existing configuration from $CONFIG_FILE" 33 + source "$CONFIG_FILE" 34 + else 35 + echo -e "${YELLOW}⚠${NC} No $CONFIG_FILE found. Please run steps 1-4 first." 36 + echo 37 + read -p "Enter your Coves instance URL [https://coves.social]: " COVES_INSTANCE_URL 38 + COVES_INSTANCE_URL=${COVES_INSTANCE_URL:-https://coves.social} 39 + fi 40 + 41 + echo 42 + echo -e "${YELLOW}═══════════════════════════════════════════════════════════${NC}" 43 + echo -e "${YELLOW} API Key Generation Process${NC}" 44 + echo -e "${YELLOW}═══════════════════════════════════════════════════════════${NC}" 45 + echo 46 + echo "API keys allow your aggregator to authenticate without managing" 47 + echo "OAuth token refresh. The key is shown ONCE and cannot be retrieved later." 48 + echo 49 + echo -e "${BLUE}Steps:${NC}" 50 + echo "1. Complete OAuth login in your browser" 51 + echo "2. Call the createApiKey endpoint" 52 + echo "3. Save the key securely" 53 + echo 54 + 55 + # Check if aggregator is indexed 56 + echo -e "${BLUE}Checking if aggregator is indexed...${NC}" 57 + if [ -n "$AGGREGATOR_DID" ]; then 58 + AGGREGATOR_CHECK=$(curl -s "${COVES_INSTANCE_URL}/xrpc/social.coves.aggregator.get?did=${AGGREGATOR_DID}" 2>/dev/null || echo "error") 59 + if echo "$AGGREGATOR_CHECK" | grep -q "error"; then 60 + echo -e "${YELLOW}⚠${NC} Could not verify aggregator status. Proceeding anyway..." 61 + else 62 + echo -e "${GREEN}✓${NC} Aggregator found in Coves instance" 63 + fi 64 + fi 65 + 66 + echo 67 + echo -e "${YELLOW}═══════════════════════════════════════════════════════════${NC}" 68 + echo -e "${YELLOW} Step 5.1: OAuth Login${NC}" 69 + echo -e "${YELLOW}═══════════════════════════════════════════════════════════${NC}" 70 + echo 71 + echo "Open this URL in your browser to authenticate:" 72 + echo 73 + AGGREGATOR_HANDLE=${AGGREGATOR_HANDLE:-"your-aggregator.example.com"} 74 + echo -e " ${BLUE}${COVES_INSTANCE_URL}/oauth/login?handle=${AGGREGATOR_HANDLE}${NC}" 75 + echo 76 + echo "This will:" 77 + echo " 1. Redirect you to your PDS for authentication" 78 + echo " 2. Return you to Coves with an OAuth session" 79 + echo 80 + echo -e "${YELLOW}After authenticating, press Enter to continue...${NC}" 81 + read 82 + 83 + echo 84 + echo -e "${YELLOW}═══════════════════════════════════════════════════════════${NC}" 85 + echo -e "${YELLOW} Step 5.2: Create API Key${NC}" 86 + echo -e "${YELLOW}═══════════════════════════════════════════════════════════${NC}" 87 + echo 88 + echo "In your browser's Developer Console (F12 → Console), run:" 89 + echo 90 + echo -e "${GREEN}fetch('/xrpc/social.coves.aggregator.createApiKey', {" 91 + echo " method: 'POST'," 92 + echo " credentials: 'include'" 93 + echo "})" 94 + echo ".then(r => r.json())" 95 + echo -e ".then(data => console.log('API Key:', data.key))${NC}" 96 + echo 97 + echo "This will return your API key. It looks like:" 98 + echo " ckapi_xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx" 99 + echo 100 + echo -e "${RED}⚠ IMPORTANT: Save this key immediately! It cannot be retrieved again.${NC}" 101 + echo 102 + read -p "Enter the API key you received: " API_KEY 103 + 104 + # Validate API key format 105 + if [[ ! $API_KEY =~ ^ckapi_[a-f0-9]{64}$ ]]; then 106 + echo -e "${RED}✗ Invalid API key format. Expected: ckapi_ followed by 64 hex characters${NC}" 107 + echo " Example: ckapi_dcbdec0a0d1b3c440125547d21fe582bbf1587d2dcd364c56ad285af841cc934" 108 + exit 1 109 + fi 110 + 111 + echo -e "${GREEN}✓${NC} API key format valid" 112 + 113 + # Save to config 114 + echo 115 + echo "COVES_API_KEY=\"$API_KEY\"" >> "$CONFIG_FILE" 116 + echo -e "${GREEN}✓${NC} API key saved to $CONFIG_FILE" 117 + 118 + echo 119 + echo -e "${YELLOW}═══════════════════════════════════════════════════════════${NC}" 120 + echo -e "${YELLOW} Step 5.3: Update Your .env File${NC}" 121 + echo -e "${YELLOW}═══════════════════════════════════════════════════════════${NC}" 122 + echo 123 + echo "Update your aggregator's .env file with:" 124 + echo 125 + echo -e "${GREEN}COVES_API_KEY=${API_KEY}${NC}" 126 + echo -e "${GREEN}COVES_API_URL=${COVES_INSTANCE_URL}${NC}" 127 + echo 128 + echo "You can remove the old AGGREGATOR_HANDLE and AGGREGATOR_PASSWORD variables." 129 + echo 130 + 131 + echo 132 + echo -e "${GREEN}╔════════════════════════════════════════════════════════════╗${NC}" 133 + echo -e "${GREEN}║ Setup Complete! ║${NC}" 134 + echo -e "${GREEN}╚════════════════════════════════════════════════════════════╝${NC}" 135 + echo 136 + echo "Your aggregator is now configured with API key authentication." 137 + echo 138 + echo "Next steps:" 139 + echo " 1. Update your aggregator's .env file with COVES_API_KEY" 140 + echo " 2. Rebuild your Docker container: docker compose build --no-cache" 141 + echo " 3. Start the aggregator: docker compose up -d" 142 + echo " 4. Check logs: docker compose logs -f" 143 + echo 144 + echo -e "${YELLOW}Security Reminders:${NC}" 145 + echo " - Never commit your API key to version control" 146 + echo " - Store it securely (environment variables or secrets manager)" 147 + echo " - Rotate periodically by generating a new key (revokes the old one)" 148 + echo
+73 -28
scripts/aggregator-setup/README.md
··· 7 7 Aggregators are automated services that post content to Coves communities. They are similar to Bluesky's feed generators and labelers. To use aggregators with Coves, you need to: 8 8 9 9 1. Create a PDS account for your aggregator (gets you a DID) 10 - 2. Prove you own a domain via `.well-known/atproto-did` 10 + 2. **(Optional)** Verify a custom domain via `.well-known/atproto-did` 11 11 3. Register with a Coves instance 12 12 4. Create a service declaration record 13 + 5. **Generate an API key** for authentication 13 14 14 15 These scripts automate this process for you. 15 16 17 + ### Handle Options 18 + 19 + You have two choices for your aggregator's handle: 20 + 21 + 1. **PDS-assigned handle** (simpler): Use the handle from your PDS, e.g., `my-aggregator.bsky.social`. No domain verification needed—skip steps 2-3. 22 + 23 + 2. **Custom domain handle** (branded): Use your own domain, e.g., `news.example.com`. Requires hosting a `.well-known/atproto-did` file on your domain. 24 + 16 25 ## Prerequisites 17 26 18 - - **Domain ownership**: You must own a domain where you can host the `.well-known/atproto-did` file 19 - - **Web server**: Ability to serve static files over HTTPS 20 27 - **Tools**: `curl`, `jq` (for JSON processing) 21 28 - **Account**: Email address for creating the PDS account 29 + - **(For custom domain only)**: Domain ownership and ability to serve HTTPS files 22 30 23 31 ## Quick Start 24 32 ··· 33 41 # Step 1: Create PDS account 34 42 ./1-create-pds-account.sh 35 43 36 - # Step 2: Generate .well-known file 37 - ./2-setup-wellknown.sh 38 - 39 - # Step 3: Register with Coves (after uploading .well-known) 40 - ./3-register-with-coves.sh 44 + # Steps 2-3: OPTIONAL - Only if you want a custom domain handle 45 + # ./2-setup-wellknown.sh 46 + # ./3-register-with-coves.sh (after uploading .well-known) 41 47 42 48 # Step 4: Create service declaration 43 49 ./4-create-service-declaration.sh 50 + 51 + # Step 5: Generate API key (requires browser for OAuth) 52 + ./5-create-api-key.sh 44 53 ``` 54 + 55 + **Minimal setup** (PDS handle only): Steps 1, 4, 5 56 + **Custom domain**: Steps 1, 2, 3, 4, 5 45 57 46 58 ### Automated Setup Example 47 59 ··· 134 146 - Updates `aggregator-config.env` with record URI and CID 135 147 - Prints record details 136 148 149 + ### 5-create-api-key.sh 150 + 151 + **Purpose**: Generates an API key for aggregator authentication 152 + 153 + **Prerequisites**: 154 + - Steps 1-4 completed 155 + - Aggregator indexed by Coves (usually takes a few seconds after step 4) 156 + - Web browser for OAuth login 157 + 158 + **What it does**: 159 + 1. Guides you through OAuth login in your browser 160 + 2. Provides the JavaScript to call the `createApiKey` endpoint 161 + 3. Validates the API key format 162 + 4. Saves the key to your config file 163 + 164 + **Outputs**: 165 + - Updates `aggregator-config.env` with `COVES_API_KEY` 166 + - Provides instructions for updating your `.env` file 167 + 168 + **Important Notes**: 169 + - The API key is shown **ONCE** and cannot be retrieved later 170 + - API keys replace password-based authentication 171 + - Keys can be revoked and regenerated at any time 172 + - Store securely - never commit to version control 173 + 137 174 ## Configuration File 138 175 139 - After running the scripts, you'll have an `aggregator-config.env` file with: 176 + After running all scripts, you'll have an `aggregator-config.env` file with: 140 177 141 178 ```bash 179 + # Identity 142 180 AGGREGATOR_DID="did:plc:..." 143 - AGGREGATOR_HANDLE="mynewsbot.bsky.social" 181 + AGGREGATOR_HANDLE="mynewsbot.example.com" 144 182 AGGREGATOR_PDS_URL="https://bsky.social" 145 - AGGREGATOR_EMAIL="bot@example.com" 146 - AGGREGATOR_PASSWORD="..." 147 - AGGREGATOR_ACCESS_JWT="..." 148 - AGGREGATOR_REFRESH_JWT="..." 149 - AGGREGATOR_DOMAIN="rss-bot.example.com" 150 - COVES_INSTANCE_URL="https://api.coves.social" 183 + AGGREGATOR_DOMAIN="mynewsbot.example.com" 184 + 185 + # Coves Instance 186 + COVES_INSTANCE_URL="https://coves.social" 151 187 SERVICE_DECLARATION_URI="at://did:plc:.../social.coves.aggregator.service/self" 152 188 SERVICE_DECLARATION_CID="..." 189 + 190 + # API Key (from Step 5) 191 + COVES_API_KEY="ckapi_..." 153 192 ``` 154 193 155 - **Use this in your aggregator code** to authenticate and post. 194 + **For your aggregator's `.env` file, you only need:** 195 + 196 + ```bash 197 + COVES_API_KEY=ckapi_xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx 198 + COVES_API_URL=https://coves.social 199 + ``` 156 200 157 201 ## What Happens Next? 158 202 159 - After completing all 4 steps: 203 + After completing all 5 steps: 160 204 161 205 1. **Your aggregator is registered** in the Coves instance's `users` table 162 206 2. **Your service declaration is indexed** in the `aggregators` table (takes a few seconds) 163 - 3. **Community moderators can now authorize** your aggregator for their communities 164 - 4. **Once authorized**, your aggregator can post to those communities 207 + 3. **Your API key is stored** and can be used for authentication 208 + 4. **Community moderators can authorize** your aggregator for their communities 209 + 5. **Your aggregator can post** to authorized communities (or all if you're a trusted aggregator) 165 210 166 211 ## Creating an Authorization 167 212 ··· 171 216 172 217 ## Posting to Communities 173 218 174 - Once authorized, your aggregator can post using: 219 + Once authorized, your aggregator can post using your API key: 175 220 176 221 ```bash 177 - curl -X POST https://api.coves.social/xrpc/social.coves.community.post.create \ 178 - -H "Authorization: DPoP $AGGREGATOR_ACCESS_JWT" \ 222 + curl -X POST https://coves.social/xrpc/social.coves.community.post.create \ 223 + -H "Authorization: Bearer $COVES_API_KEY" \ 179 224 -H "Content-Type: application/json" \ 180 225 -d '{ 181 - "communityDid": "did:plc:...", 182 - "post": { 183 - "text": "Your post content", 184 - "createdAt": "2024-01-15T12:00:00Z" 185 - } 226 + "community": "c-worldnews.coves.social", 227 + "content": "Your post content", 228 + "facets": [] 186 229 }' 187 230 ``` 231 + 232 + The API key handles all authentication - no OAuth token refresh needed. 188 233 189 234 ## Troubleshooting 190 235