feat(api): add personal API tokens and enhance webhook integration UI

- Add ApiToken model with SHA-256 hashed storage and usage tracking
- Create API token CRUD endpoints (POST/GET/DELETE /api/api-tokens/)
- Add Bearer token authentication to require_login decorator
- Exempt Bearer-authenticated requests from CSRF validation
- Add API tokens management page with create/revoke/copy UI
- Enhance webhook integration type with detailed explanation and code snippets
- Add navigation links (desktop + mobile) to API tokens page
- Include 19 tests covering CRUD, auth resolution, and utility functions
- Create migration 024_add_api_tokens

Co-authored-by: christianlouis <361235+christianlouis@users.noreply.github.com>
This commit is contained in:
copilot-swe-agent[bot]
2026-03-08 18:42:55 +00:00
parent 906c1ca246
commit c3bb93c197
13 changed files with 1272 additions and 25 deletions
+15
View File
@@ -209,6 +209,9 @@ function _makeMenuLink(href, iconClass, label, extraClasses = '') {
linksDiv.appendChild(
_makeMenuLink('/subscription', 'fas fa-layer-group text-indigo-400', 'My Subscription', 'text-gray-700')
);
linksDiv.appendChild(
_makeMenuLink('/api-tokens', 'fas fa-key text-yellow-500', 'API Tokens', 'text-gray-700')
);
// Divider + Sign Out
const divider = document.createElement('div');
@@ -278,6 +281,18 @@ function _makeMenuLink(href, iconClass, label, extraClasses = '') {
subLink.appendChild(document.createTextNode('My Subscription'));
mobileAuthSection.appendChild(subLink);
// API Tokens link
const tokensLink = document.createElement('a');
tokensLink.href = '/api-tokens';
tokensLink.className =
'flex items-center px-3 py-3 rounded-md text-base font-medium text-gray-700 hover:text-gray-900 hover:bg-gray-50';
const tokensIcon = document.createElement('i');
tokensIcon.className = 'fas fa-key mr-2 text-yellow-500';
tokensIcon.setAttribute('aria-hidden', 'true');
tokensLink.appendChild(tokensIcon);
tokensLink.appendChild(document.createTextNode('API Tokens'));
mobileAuthSection.appendChild(tokensLink);
// Logout link
const logoutLink = document.createElement('a');
logoutLink.href = '/logout';