Skip to main content
Glama
API_KEYS_TESTING_GUIDE.md9.67 kB
# API Key Management - Testing Guide ## Overview This guide covers testing the API Key Management feature (User Story 2, Tasks T026-T033). ## Implemented Files ### Backend (Server-side) - `/dashboard/app/(dashboard)/api-keys/page.tsx` - Server Component for API keys page - `/dashboard/app/(dashboard)/api-keys/actions.ts` - Server Actions for CRUD operations ### Frontend (Client-side) - `/dashboard/components/api-keys/APIKeyList.tsx` - List display and actions - `/dashboard/components/api-keys/APIKeyGenerateModal.tsx` - Modal for generation - `/dashboard/components/api-keys/APIKeyDisplay.tsx` - Display with copy functionality ## Features Implemented ### T026 - API Keys Management Page - **Route:** `/api-keys` - **Authentication:** Required (redirects to `/login` if not authenticated) - **Features:** - Displays all API keys (active and inactive) for user's organization - Shows warning when 5 active keys limit reached - Security best practices notice - Sorted by creation date (newest first) ### T027 - Generate API Key Server Action - **Function:** `generateApiKey()` - **Security:** - Generates secure random API key: `mcp_<32 random chars>` - Uses `crypto.randomBytes(24)` for randomness - SHA-256 hash stored in database (never the full key) - **Validation:** - Checks user authentication - Verifies organization membership - Enforces 5 active keys limit per organization - **Returns:** Full API key (shown once) or error message ### T028 - Delete API Key Server Action - **Function:** `deleteApiKey(keyId: number)` - **Security:** - Verifies key belongs to user's organization - Soft delete (sets `is_active = false`) - **Confirmation:** Browser confirmation dialog before deletion ### T029 - Regenerate API Key Server Action - **Function:** `regenerateApiKey(keyId: number)` - **Process:** 1. Marks old key as inactive 2. Generates new random key 3. Returns new full key (shown once) - **Confirmation:** Browser confirmation dialog before regeneration ### T030 - APIKeyList Component - **Display Features:** - Masked key hash: First 6 chars + "..." + last 6 chars - Created date (formatted) - Last used date (or "Never used") - Status badge (Active/Inactive) - Empty state with helpful message - **Actions:** - Generate New Key button - Regenerate button (per active key) - Delete button (per active key) - Loading states for async operations ### T031 - APIKeyGenerateModal Component - **States:** - Initial: Shows warning, Generate button - Generating: Loading spinner - Success: Shows full API key with copy button - Error: Shows error message - **Security:** - Forces user acknowledgment ("I've saved my key" button) - Cannot be accidentally closed (must click button) ### T032 - APIKeyDisplay Component - **Features:** - Monospace code block display - Copy to clipboard button with visual feedback - Shows checkmark for 2 seconds after copy - Security warning: "This is the only time you'll see this key" ### T033 - Max 5 Keys Validation - **Implementation:** - Checked in `generateApiKey()` Server Action - Counts active keys before insertion - Returns error if limit reached - UI shows warning banner when at limit - Generate button disabled when at limit ## Testing Checklist ### Setup - [ ] Database has `api_keys` table with correct schema - [ ] User is authenticated and has organization membership - [ ] Navigate to `/api-keys` page ### Generate API Key (Happy Path) - [ ] Click "Generate New Key" button - [ ] Modal opens with warning message - [ ] Click "Generate Key" button - [ ] Loading spinner appears - [ ] Success state shows full API key in monospace font - [ ] API key format: `mcp_<32 random characters>` - [ ] Copy button works and shows checkmark - [ ] Security warning is visible - [ ] Click "I've saved my key" button - [ ] Modal closes - [ ] New key appears in the list - [ ] New key shows as "Active" - [ ] Last used shows "Never used" ### API Key List Display - [ ] Keys are sorted by creation date (newest first) - [ ] Key hash is masked (first 6 + "..." + last 6) - [ ] Created date is formatted correctly - [ ] Active keys show green "Active" badge - [ ] Inactive keys show gray "Inactive" badge - [ ] Active keys have Regenerate and Delete buttons - [ ] Inactive keys do not have action buttons ### Delete API Key - [ ] Click Delete button on an active key - [ ] Confirmation dialog appears - [ ] Confirm deletion - [ ] Loading state appears on button - [ ] Key status changes to "Inactive" - [ ] Action buttons disappear for that key - [ ] Page updates without full refresh ### Regenerate API Key - [ ] Click Regenerate button on an active key - [ ] Confirmation dialog appears - [ ] Confirm regeneration - [ ] Modal opens showing generation progress - [ ] New API key is displayed - [ ] New API key is different from old one - [ ] Copy button works for new key - [ ] Close modal - [ ] Old key is marked as Inactive - [ ] New key appears in list as Active ### 5 Keys Limit (Edge Case) - [ ] Generate 5 active API keys - [ ] Warning banner appears: "Maximum limit reached..." - [ ] Generate button becomes disabled and grayed out - [ ] Hover shows cursor-not-allowed - [ ] Delete one active key - [ ] Warning banner disappears - [ ] Generate button becomes enabled again - [ ] Can generate new key successfully ### Error Handling - [ ] Try generating key when not authenticated → redirects to login - [ ] Try accessing page without organization → redirects to login - [ ] Try deleting key from another organization → shows error message - [ ] Database error during generation → shows error in modal - [ ] Network error → shows appropriate error message ### Security Verification - [ ] Inspect database: only key hash is stored (64 hex characters) - [ ] Full API key is never logged in console - [ ] API key shown only once during generation - [ ] Cannot retrieve full key after modal closes - [ ] Inactive keys cannot be used for authentication (verify in MCP server) ### Accessibility - [ ] Keyboard navigation works throughout - [ ] Focus states visible on all interactive elements - [ ] Screen reader announces button states - [ ] Color contrast meets WCAG AA standards - [ ] Error messages are announced ### Responsive Design - [ ] Layout works on mobile (320px width) - [ ] Layout works on tablet (768px width) - [ ] Layout works on desktop (1280px+ width) - [ ] Buttons stack properly on small screens - [ ] Modal is scrollable on small screens - [ ] Code block doesn't overflow ### Performance - [ ] Page loads in < 3 seconds - [ ] No layout shift during key list load - [ ] Smooth transitions for modal open/close - [ ] No unnecessary re-renders - [ ] Copy to clipboard responds instantly ## Known Limitations 1. **One-time Display:** API keys are shown only once. If user closes modal without copying, they must regenerate. 2. **Soft Delete:** Deleted keys remain in database with `is_active = false` for audit trail. 3. **No Edit:** Keys cannot be edited, only regenerated or deleted. 4. **Browser Clipboard:** Copy functionality requires HTTPS in production. ## Integration Points ### Database - Table: `api_keys` - Functions used: - Standard CRUD via Supabase client - `update_api_key_last_used()` (called by MCP server, not dashboard) ### Authentication - Uses Supabase Auth via Server Components - Checks `organization_members` table for org membership - Server Actions verify auth on every request ### MCP Server Integration - Generated API keys will be used in Claude Desktop config - MCP server validates keys using `get_organization_by_api_key()` function - Format: `X-API-Key: mcp_xxxxxxxxxxxxx` header ## Troubleshooting ### Issue: "Not authenticated" error **Solution:** Ensure user is logged in and has valid session ### Issue: "No organization found" error **Solution:** User must be member of an organization (check `organization_members` table) ### Issue: Copy button doesn't work **Solution:** - Check browser supports `navigator.clipboard` - Ensure site is served over HTTPS (or localhost) - Check browser permissions for clipboard access ### Issue: Keys not appearing in list **Solution:** - Check browser console for errors - Verify Supabase RLS policies allow reading - Ensure `organization_id` matches user's org ### Issue: Build errors **Solution:** - Run `npm install @headlessui/react` (required dependency) - Check TypeScript errors with `npm run build` ## Files Modified/Created ``` dashboard/ ├── app/ │ └── (dashboard)/ │ └── api-keys/ │ ├── page.tsx (NEW) │ └── actions.ts (NEW) └── components/ └── api-keys/ ├── APIKeyList.tsx (NEW) ├── APIKeyGenerateModal.tsx (NEW) └── APIKeyDisplay.tsx (NEW) package.json (MODIFIED - added @headlessui/react) ``` ## Next Steps After successful testing: 1. **Database Migration:** Ensure `api_keys` table exists in production 2. **Environment Variables:** Verify Supabase credentials are set 3. **RLS Policies:** Confirm Row Level Security policies are in place 4. **MCP Server:** Update MCP server to validate API keys 5. **Documentation:** Update user-facing docs with API key setup instructions 6. **Monitoring:** Add logging for API key usage and errors ## Security Notes - ✅ API keys use cryptographically secure randomness - ✅ Only SHA-256 hashes stored in database - ✅ Full keys shown only once - ✅ Server-side validation on all actions - ✅ Organization isolation enforced - ✅ Soft delete maintains audit trail - ✅ No API keys in client-side state after modal close

Latest Blog Posts

MCP directory API

We provide all the information about MCP servers via our MCP API.

curl -X GET 'https://glama.ai/api/mcp/v1/servers/darrentmorgan/hostaway-mcp'

If you have feedback or need assistance with the MCP directory API, please join our Discord server