--- name: openclaw-m2m-openapi description: Implement and maintain OpenAPI plus machine-to-machine access for FEDEO/OpenClaw-style Fastify backends. Use when creating tenant-bound API keys, authenticating M2M callers, exchanging API keys for short-lived JWTs, exposing OpenAPI docs/spec endpoints, and ensuring req.user is populated for impersonated tenant/user execution. --- # OpenClaw M2M + OpenAPI Implement OpenAPI publication and M2M authentication with tenant+user impersonation. ## Define Data Model Create a DB table for M2M API keys with at least: - Key identity: `id`, `name`, `key_prefix`, `key_hash` - Scope: `tenant_id`, `user_id` - Lifecycle: `active`, `expires_at`, `last_used_at`, `created_at`, `updated_at` - Auditing: `created_by` Store only a hash (`sha256`) of the key, never plaintext. ## Publish OpenAPI Configure Fastify Swagger dynamically and expose: - UI endpoint: `/docs` - Raw spec endpoint: `/openapi.json` Define OpenAPI metadata and bearer auth security schema (`bearerAuth`). ## Implement M2M Authentication In M2M auth plugin: 1. Read API key from `x-api-key`. 2. Hash and compare against `key_hash` in DB. 3. Reject missing/invalid/inactive/expired keys with 401. 4. Load mapped tenant/user. 5. Populate `req.user` with: - `user_id` - `email` - `tenant_id` 6. Update key usage metadata (`last_used_at`, `updated_at`). Always keep `req.user` compatible with existing JWT-authenticated route expectations. ## Implement API Key Management Expose tenant-scoped management endpoints on authenticated API routes: - `GET /api/tenant/api-keys` - `POST /api/tenant/api-keys` - `PATCH /api/tenant/api-keys/:id` - `DELETE /api/tenant/api-keys/:id` For create: - Generate random plaintext key once. - Return plaintext only in create response. - Persist only hash + prefix. - Enforce that selected `user_id` belongs to current tenant. ## Add Token Exchange (Preferred M2M Flow) Expose internal route: - `POST /internal/auth/m2m/token` Behavior: 1. Require M2M-authenticated request. 2. Revalidate tenant membership of impersonated user. 3. Issue short-lived JWT signed with app JWT secret. 4. JWT payload must include `user_id`, `email`, `tenant_id`. Use this JWT for normal `/api/*` requests via `Authorization: Bearer `. ## Security Rules - Never log full API keys. - Enforce TTL bounds for exchanged JWTs (e.g. 60..3600 seconds). - Treat expired keys as unauthorized. - Keep key hash comparison deterministic and normalized. - Keep management endpoints tenant-isolated. ## Verification Checklist Run and verify: 1. Backend build passes. 2. OpenAPI UI and raw spec are reachable. 3. API key create/list/update/delete works per tenant. 4. Exchange endpoint returns JWT. 5. JWT can call `/api/me` and shows impersonated tenant/user. ## Quick Commands ```bash # Build backend npm run build # Exchange key for JWT curl -X POST http://localhost:3000/internal/auth/m2m/token \ -H "x-api-key: " \ -H "Content-Type: application/json" \ -d '{"expires_in_seconds":900}' # Use exchanged JWT on normal API curl http://localhost:3000/api/me \ -H "Authorization: Bearer " ```