feat(api-tokens): add PAT management UI, CSRF handling, and auth-loading fixes

Add an API tokens management route to create, list, and revoke PATs, showing
the plaintext token once on creation with scope and server-id selection.

Mirror the nz-csrf cookie into the X-CSRF-Token header on unsafe fetcher
methods (POST/PUT/PATCH/DELETE) for the server-side double-submit check, and
self-heal expired sessions via refresh-token without a recursive fetch loop.

Gate protected routes behind resolved auth state to avoid pre-auth SWR fetches,
and fix the login loading/race so stale probes cannot clobber the session.

Add i18n keys for the new screens across all locales.

Co-authored-by: cloudcode <cloudcode@users.noreply.github.com>
This commit is contained in:
naiba
2026-05-30 15:56:53 +00:00
co-authored by cloudcode
parent f47d4a8772
commit f07c557029
37 changed files with 2041 additions and 69 deletions
+25 -1
View File
@@ -254,5 +254,29 @@
"CopiedToClipboard": "Copiar al portapapeles",
"ClipboardWriteFailed": "Error al escribir en el portapapeles",
"PastedFromClipboard": "Pegado del portapapeles",
"ClipboardReadFailed": "Falló la lectura del portapapeles"
"ClipboardReadFailed": "Falló la lectura del portapapeles",
"EnableMCP": "Enable MCP endpoint (off by default; review API token scopes and server allow-list first)",
"ApiTokens": "API Tokens",
"CreateApiToken": "Create API token",
"CreateApiTokenDescription": "Tokens authenticate MCP and external clients on your behalf. They cannot exceed your own permissions.",
"ConfirmDeleteApiToken": "Revoke API token '{{name}}'? This cannot be undone.",
"ApiTokenRevoked": "API token revoked.",
"ApiTokenCreated": "API token created",
"ApiTokenRevealOnce": "Copy this token now. It will never be shown again.",
"ApiTokenStoreSafely": "Treat this token like a password. Anyone with it can act on your behalf within its scopes.",
"ApiTokenServers": "Servers",
"ApiTokenAllServers": "all permitted",
"ApiTokenNever": "never",
"ApiTokenExpiresAt": "Expires",
"ApiTokenLastUsed": "Last used",
"ApiTokenServerIDs": "Restrict to server IDs (optional)",
"ApiTokenServerIDsPlaceholder": "comma-separated, e.g. 1,2,3",
"ApiTokenExpiresInDays": "Expires in (days, 0 = never)",
"ApiTokenScopeRequired": "At least one scope is required.",
"ApiTokenServersInvalid": "Server IDs must be positive integers.",
"ApiTokenExpiryInvalid": "Days must be between 0 and 3650.",
"NameRequired": "Name is required.",
"Revoke": "Revoke",
"Copied": "Copied to clipboard",
"Scopes": "Scopes"
}