Package reference
Mirrors the package README (single source). Install @basaltkit/api-keys-ui v1.3.0 — npm · source.
<p align="center"> <a href="https://basaltkit-docs.pages.dev"> <img src="https://basaltkit-docs.pages.dev/social-card.png" alt="Basalt" width="440"> </a> </p>
@basaltkit/api-keys-ui
Self-contained HTML page to manage API keys for @basaltkit/auth: create (shows the key once), list and revoke — zero dependencies, no build step. You need this module when you want to give users a screen to manage their API keys without building the UI from scratch.
What this module solves
@basaltkit/auth already exposes the POST/GET /apikeys and DELETE /apikeys/:id routes (the plaintext key only appears on creation). This module is the UI on top of them: a page that lists the keys, lets you create a new one (revealing the secret once, with a copy button) and revoke existing ones.
Installation
pnpm add @basaltkit/api-keys-uiDepends on @basaltkit/core and @basaltkit/fastify. Requires your app to mount the API key routes from @basaltkit/auth (apiKeysPlugin + apiKeyRoutes).
Getting started in 5 minutes
import { createApp } from '@basaltkit/core'
import { authPlugin, authRoutes, apiKeysPlugin, apiKeyRoutes, MemoryUserSource } from '@basaltkit/auth'
import { apiKeysUiRoutes } from '@basaltkit/api-keys-ui'
import { fastifyPlugin } from '@basaltkit/fastify'
const app = await createApp({
plugins: [
authPlugin({ users: new MemoryUserSource(), secret: process.env.JWT_SECRET! }),
apiKeysPlugin(),
fastifyPlugin({
routes: [
...authRoutes(),
...apiKeyRoutes(), // POST/GET /apikeys, DELETE /apikeys/:id
...apiKeysUiRoutes(), // GET /apikeys/ui ← the page
],
}),
],
}).boot()Open /apikeys/ui (authenticated) and the user can create, view and revoke their keys.
Log in through /auth/login before opening the page. The login route sets the HttpOnly browser session cookie; the page uses same-origin requests and sends that cookie automatically:
curl -c cookies.txt -X POST http://localhost:3000/auth/login \
-H 'content-type: application/json' \
-d '{"email":"ada@example.com","password":"secretpassword1"}'
curl -b cookies.txt http://localhost:3000/apikeys/uiDo not modify the page to read a JWT from localStorage. The supported browser flow is the HttpOnly cookie.
How it works
The page is served by GET /apikeys/ui (requires login). In the browser, it calls the JSON routes with credentials: 'same-origin', so it assumes the user's session is already authenticated against ${apiBase}/apikeys. When creating a key, it reveals the secret once (with a warning and a copy button) — after that only the prefix is visible, as required by @basaltkit/auth's security model.
API reference
apiKeysUiRoutes({ path?, apiBase?, title? })
Returns the route that serves the page. path (default /apikeys/ui), apiBase (where the JSON routes are, default same-origin), title. The page relies on same-origin session credentials. The create form accepts an optional expiration date, which the server validates again. authRoutes() issues a HttpOnly session cookie on login, and the browser sends it automatically to the JSON API routes. The access JWT remains in the login response for non-browser clients and is not copied to localStorage by this UI.
apiKeysPageHtml({ apiBase?, title? })
Returns the page's HTML as a string — use it directly if you want to serve it your own way (or on another framework).
Content-Security-Policy
The route sets a route-scoped CSP by default: everything locked down and the page's inline script allowed only by sha256 hash (exported as apiKeysPageCsp). It works under securityPlugin's strict app-wide CSP — do not disable CSP globally. Override with csp: '…' or opt out with csp: false; if you serve the raw HTML string yourself, set the matching CSP header on that route. Server-side inputs are HTML-escaped and embedded state cannot terminate the script block.
How it connects to other modules
@basaltkit/auth— provides the API key routes this page consumes (apiKeysPlugin+apiKeyRoutes).@basaltkit/permissions— add a guard to the page route if you want to restrict who can see it.