A runnable Next.js example for collecting credentials with @onkernel/vault-react. The browser renders Kernel's unstyled credential form while a same-origin backend keeps the Kernel API key private and maps one-time bearer capabilities to vault items.
Requires Bun and Node.js 20.9 or newer.
cp .env.example .env.local
bun install
bun run devIn a second terminal, create a 15-minute collection link:
bun run create-requestOpen the printed URL. Mock mode exercises the complete browser/backend flow without calling Kernel. Do not enter real credentials in mock mode.
- Set
MOCK_VAULT=falseandKERNEL_API_KEYin.env.local. - Create a credential item in a Kernel vault.
- Generate a link for that item:
bun run create-request -- <vault-id-or-name> <item-key>The command retrieves the item's immutable ID, generates 32 random bytes, stores only the SHA-256 token digest, and prints the raw token once in this form:
https://app.example.com/credentials/collect#token=<43-character-base64url-token>
The fragment is not sent in page requests or referrers. The page sends it only in an Authorization: Bearer <token> header to the same-origin /api/credential-requests/current endpoint.
app/credentials/collectreads and clears the fragment capability and rendersCredentialForm.app/api/credential-requests/currentserves safe item data and accepts versioned field edits.lib/collection-handler.tsvalidates the bearer, origin, target, item ID, version, field names, value sizes, and body size.lib/vault-client.tscontains real and mock vault adapters. Only the real adapter receivesKERNEL_API_KEY.lib/request-store.tsdefines the durableCollectionRequestStoreboundary.scripts/create-request.tscreates a short-lived link without persisting the raw token.
Successful submissions mark the mapping consumed. Kernel writes include both the rendered version and immutable item ID, so a stale form or a deleted-and-recreated key cannot redirect a write.
FileCollectionRequestStore is intentionally local-only. Its atomic file replacement prevents torn files, but it does not coordinate multiple processes and most serverless filesystems are ephemeral.
Before deployment, implement CollectionRequestStore with your database and replace the construction in lib/runtime.ts. Persist:
{
id,
tokenDigest,
vaultId,
itemKey,
itemId,
expiresAt,
consumedAt,
revokedAt,
}Add any signed-in application user ID needed by your authorization model. Verify that user in addition to the bearer on every read and write. Make consumption and revocation atomic in the database.
- Set
APP_ORIGINto the exact HTTPS origin serving the page. - Set
MOCK_VAULT=falseand provideKERNEL_API_KEYonly to the server runtime. - Replace the file store with a durable database implementation.
- Deliver links through a channel suitable for password-reset links and keep expiry short.
- Exclude URLs, fragments, authorization headers, request bodies, credentials, and upstream errors from logs, analytics, traces, and session replay.
The customer page and backend receive raw entered values. They are trusted application code, not an isolated Kernel collector. Keep the collection route free of third-party scripts and preserve the response's no-store and no-referrer policies.
bun run typecheck
bun run test
bun run buildMIT