feat: add API key authentication system and update documentation

API Key System:
- Add TpmjsApiKey, ApiUsageRecord, ApiUsageSummary models to schema
- Create API key utilities (generate, hash, mask with tpmjs_sk_ prefix)
- Implement dual auth middleware (session + API key)
- Add rate limiting with Vercel KV
- Create CRUD endpoints for API key management
- Add usage tracking and analytics endpoint
- Build API key management UI in dashboard
- Build usage dashboard with charts

Route Protection:
- Require auth for MCP endpoints (mcp:execute scope)
- Require auth for agent chat (agent:chat scope)
- Require auth for bridge connections (bridge:connect scope)

Documentation Updates:
- Update all curl/fetch examples with Authorization header
- Document API key format, scopes, and rate limits
- Update PRD-MCP-BRIDGE.md, MCP-AGGREGATOR-DESIGN.md
- Update API docs page with auth requirements
- Update HOW_TO_PUBLISH_A_TOOL.md
This commit is contained in:
Ajax Davis 2026-01-13 04:45:52 +10:00
parent b663ca3e05
commit a3f1f3935e
20 changed files with 2813 additions and 90 deletions

View file

@ -401,9 +401,9 @@ class TPMJSBridge {
})));
}
// 3. Connect to TPMJS WebSocket
// 3. Connect to TPMJS WebSocket (requires API key with bridge:connect scope)
this.ws = new WebSocket(
`${this.config.tpmjsUrl}/api/bridge?token=${this.config.apiKey}`
`${this.config.tpmjsUrl}/api/bridge?token=${this.config.apiKey}` // apiKey format: tpmjs_sk_...
);
this.ws.on('open', () => {
@ -443,6 +443,7 @@ class TPMJSBridge {
}
// CLI entry point
// API key is loaded from ~/.tpmjs/credentials.json (format: tpmjs_sk_...)
const config = loadConfig(); // from ~/.tpmjs/bridge.json
const bridge = new TPMJSBridge(config);
bridge.start();
@ -452,9 +453,12 @@ bridge.start();
Server-side handler for bridge connections.
**Authentication:** Requires TPMJS API key (format: `tpmjs_sk_...`) with `bridge:connect` scope.
```typescript
// apps/web/src/app/api/bridge/route.ts
import { prisma } from '@tpmjs/db';
import { authenticateRequest, hasScope } from '~/lib/api-keys/middleware';
export const runtime = 'nodejs';
@ -463,9 +467,9 @@ export async function GET(request: Request) {
const { searchParams } = new URL(request.url);
const token = searchParams.get('token');
// Validate API key
const user = await validateApiKey(token);
if (!user) {
// Validate API key (must have bridge:connect scope)
const authResult = await authenticateRequest();
if (!authResult.authenticated || !hasScope(authResult, 'bridge:connect')) {
return new Response('Unauthorized', { status: 401 });
}
@ -715,11 +719,19 @@ interface ToolExecutionError {
### Security Considerations
1. **API Key Authentication**: Bridge connections require valid API key
2. **User Isolation**: Each user's bridge is isolated
3. **Tool Whitelisting**: Users explicitly add tools to collections
4. **Encrypted Credentials**: Remote MCP server credentials encrypted at rest
5. **WebSocket Security**: WSS (TLS) required for bridge connections
1. **API Key Authentication**: All API endpoints require a valid TPMJS API key (`tpmjs_sk_...` prefix)
2. **Scope-Based Access**: API keys have specific scopes (e.g., `bridge:connect`, `mcp:execute`, `agent:chat`)
3. **User Isolation**: Each user's bridge is isolated
4. **Tool Whitelisting**: Users explicitly add tools to collections
5. **Encrypted Credentials**: Remote MCP server credentials encrypted at rest
6. **WebSocket Security**: WSS (TLS) required for bridge connections
**Required API Key Scopes:**
- `bridge:connect` - For bridge WebSocket connections
- `mcp:execute` - For MCP tool execution
- `collection:read` - For accessing collection data
Generate API keys from Settings > TPMJS API Keys in the dashboard.
---
@ -819,12 +831,17 @@ After setup, user only needs ONE MCP server in their config:
"mcpServers": {
"tpmjs": {
"type": "url",
"url": "https://tpmjs.com/api/mcp/username/all-my-tools/http"
"url": "https://tpmjs.com/api/mcp/username/all-my-tools/http",
"headers": {
"Authorization": "Bearer tpmjs_sk_your_api_key_here"
}
}
}
}
```
**Note:** Generate your API key from Settings > TPMJS API Keys. The key requires `mcp:execute` scope.
This single endpoint provides access to:
- All npm tools in the collection
- All remote MCP tools configured

View file

@ -648,7 +648,7 @@ npx @tpmjs/bridge <command>
**~/.tpmjs/credentials.json**
```json
{
"apiKey": "tpmjs_xxxxxxxxxxxxxxxxxxxx",
"apiKey": "tpmjs_sk_xxxxxxxxxxxxxxxxxxxx",
"userId": "user_abc123",
"email": "user@example.com",
"expiresAt": "2026-01-12T00:00:00Z"
@ -703,9 +703,11 @@ await manager.disconnect('chrome');
#### Connection
```
wss://tpmjs.com/api/bridge?token=tpmjs_xxxx
wss://tpmjs.com/api/bridge?token=tpmjs_sk_your_api_key_here
```
**Note:** All TPMJS API endpoints require authentication. Generate an API key from your dashboard at Settings > TPMJS API Keys. API keys use the `tpmjs_sk_` prefix.
#### Messages: Bridge → TPMJS
**Register Tools**
@ -907,16 +909,28 @@ ALTER TABLE "CollectionBridgeTool" ADD CONSTRAINT "CollectionBridgeTool_collecti
**Endpoint**: `GET /api/bridge`
**Query Parameters**:
- `token` (required): User's API key
- `token` (required): User's TPMJS API key (format: `tpmjs_sk_...`)
**Upgrade**: WebSocket
**Authentication**: Validates API key, returns 401 if invalid
**Authentication**: Validates API key with `bridge:connect` scope, returns 401 if invalid
**Example**:
```bash
# Connect via WebSocket with API key
wscat -c 'wss://tpmjs.com/api/bridge?token=tpmjs_sk_your_api_key_here'
```
### Bridge Status API
**Endpoint**: `GET /api/user/bridge`
**Authentication**: Requires API key with `bridge:connect` scope
```bash
curl https://tpmjs.com/api/user/bridge \
-H 'Authorization: Bearer tpmjs_sk_your_api_key_here'
```
**Response**:
```json
{
@ -945,13 +959,18 @@ ALTER TABLE "CollectionBridgeTool" ADD CONSTRAINT "CollectionBridgeTool_collecti
### Collection Bridge Tools API
All collection endpoints require API key with `collection:read` scope.
**Add Tool**: `POST /api/collections/{id}/bridge-tools`
```json
{
"serverId": "chrome-devtools",
"toolName": "screenshot"
}
```bash
curl -X POST 'https://tpmjs.com/api/collections/{id}/bridge-tools' \
-H 'Authorization: Bearer tpmjs_sk_your_api_key_here' \
-H 'Content-Type: application/json' \
-d '{
"serverId": "chrome-devtools",
"toolName": "screenshot"
}'
```
**Remove Tool**: `DELETE /api/collections/{id}/bridge-tools/{toolId}`

View file

@ -159,8 +159,9 @@ This happened with the `startTime is not defined` bug. Our executor code had a b
### Investigating a Specific Tool
```bash
# Check current health status
curl -s 'https://tpmjs.com/api/tools?limit=50' | \
# Check current health status (requires API key)
curl -s 'https://tpmjs.com/api/tools?limit=50' \
-H 'Authorization: Bearer tpmjs_sk_your_api_key_here' | \
jq '.data[] | select(.package.npmPackageName == "PACKAGE_NAME") | {
packageName: .package.npmPackageName,
exportName: .exportName,
@ -179,10 +180,11 @@ cat package/dist/index.js
### Manually Updating Health Status
For testing or correction:
For testing or correction (requires API key with appropriate scope):
```bash
curl -X POST 'https://tpmjs.com/api/tools/report-health' \
-H 'Authorization: Bearer tpmjs_sk_your_api_key_here' \
-H 'Content-Type: application/json' \
-d '{
"packageName": "@scope/package",