@keyring-dev/react
v0.1.1
Published
Embeddable React component for the Keyring embed plane. Browser-only: holds an embed token, never a secret key.
Readme
@keyring-dev/react
An embeddable React component for the Keyring embed plane: drop it into a vendor's dashboard and their own customer can list, create, rotate and revoke their own API keys, scoped to their own tenant.
import { KeyringKeys } from '@keyring-dev/react';
import { mintEmbedToken } from './actions';
export default function KeysPage() {
return (
<KeyringKeys
getToken={mintEmbedToken}
baseUrl={process.env.KEYRING_BASE_URL!}
/>
);
}mintEmbedToken is a Server Action (or any async function) that exchanges the
vendor's own krsk_ secret key for a five-minute embed token scoped to one
tenant, via POST /v1/embed_tokens. See the Keyring docs for the full
quickstart: the page above, the action that mints the token, the required
app/layout.tsx, and the exact dependencies.
Install
npm install @keyring-dev/reactreact and react-dom (^18.3.0 or ^19.0.0) are peer dependencies.
The getToken() contract
getToken: () => Promise<string>;- Called once on mount, and again before the token it returned expires —
the component reads
expires_in(seconds remaining) fromGET /v1/embed/sessionand schedules the next refresh againstperformance.now()at receipt, never against the browser's wall clock, so a skewed client clock cannot make it refresh in a storm or admit a stale credential. - If it rejects, or a token it returns is refused by the embed plane on any
call — session, list, create, rotate, or revoke — the component shows a
re-authentication state with a "Reconnect" button that calls
getToken()again. It never falls back to a longer-lived credential, and never retries a request with the token that was just refused, because it never holds anything else — this package has no code path that accepts, stores, or sends akrsk_secret key. A token that is not JWT-shaped, or that starts withkrsk_, is refused before any network call. - A returned token should already be scoped the way the vendor wants: which
keys:read/keys:writecapabilities the session has, and whichkey_scope:<name>values it may put on a key it mints, are both decided at mint time on the vendor's server, never by this component.
Props
interface KeyringKeysProps {
getToken: () => Promise<string>;
baseUrl: string;
className?: string;
}baseUrl is required and has no default: point it at your own Keyring
deployment. The component never guesses a host.
What it never does
- Never accepts, stores, sends, or has an import path that could reach a
krsk_secret key. The only credential this package's code can hold is whatevergetToken()returns, and even that is refused before use if it looks like a secret key rather than an embed token. - Never shows a newly minted or rotated key's plaintext more than once, and
never re-displays a dismissed one — there is no control that can reopen it.
The reveal panel only ever renders from the state the create/rotate call
just returned, stays mounted across a re-authentication so an
unacknowledged plaintext is not lost underneath it, and Create, Rotate and
Revoke are disabled while it is open. A rotated key's
previous_keyis deliberately not shown as a secret, only as the revoked/expiring record it now is. - Never sends a second create, rotate, or revoke request for one click or double click — mutations are single-flight.
- Never renders a create, rotate, or revoke control the token's own
scopesdon't grant. A read-only embed token (keys:readonly) renders a read-only list. - Never talks to anything but the Keyring embed plane (
/v1/embed/*) atbaseUrl. No analytics, no third-party script, no iframe.
Markup
Minimal and unstyled. Every element carries a keyring-keys__* class hook so
a host can style it; there is no theming system in this version. Class names:
keyring-keys, keyring-keys--loading, keyring-keys--reauth,
keyring-keys__header, keyring-keys__badge--test, keyring-keys__create,
keyring-keys__list, keyring-keys__row, keyring-keys__reveal,
keyring-keys__reconnect.
Out of scope for this version
Web component and iframe builds, theming tokens, and a request-log/usage component are cut for v1. This package ships React only.
