docs: update portal for WRNexusJS 0.8.0
This commit is contained in:
+130
-6
@@ -10,11 +10,11 @@ page wrnexusjwt {
|
||||
<header class="topbar">
|
||||
<a class="brand" href="/"><span>W</span> WRNexusJS</a>
|
||||
<nav aria-label="Primary"><a href="/getting-started">Get started</a><a href="/packages">Packages</a><a href="https://component.wrnexusjs.dev/">Components</a><a href="/language">Language</a><a href="/architecture">Architecture</a></nav>
|
||||
<div class="topbar-actions"><a class="preview-pill" href="/access">Private preview · v0.7.0</a><button data-wire-theme-toggle class="theme-button" aria-label="Toggle color theme" title="Toggle color theme">◐</button></div>
|
||||
<div class="topbar-actions"><a class="preview-pill" href="/access">Private preview · v0.8.0</a><button data-wire-theme-toggle class="theme-button" aria-label="Toggle color theme" title="Toggle color theme">◐</button></div>
|
||||
</header>
|
||||
<div class="mobile-doc-nav"><details><summary>Browse documentation</summary><nav><a href="/getting-started">Get started</a><a href="/packages">Packages</a><a href="https://component.wrnexusjs.dev/">Components</a><a href="/language">Language</a><a href="/architecture">Architecture</a><a href="/tutorial">Tutorial</a><a href="/guides/project-structure">Guides</a><a href="/examples">Examples</a><a href="/search">Search</a></nav></details></div>
|
||||
<main class="portal-main docs-layout">
|
||||
<article id="main" class="documentation prose standalone package-document"><nav class="breadcrumbs" aria-label="Breadcrumb"><a href="/">Home</a><span>/</span><a href="/packages">Packages</a><span>/</span><span aria-current="page">@wrnexus/jwt</span></nav><section class="doc-intro"><span class="eyebrow">Security · Package reference</span><h1>@wrnexus/jwt</h1><p>HS256 JWT signing, verification, and bearer authentication.</p><div class="doc-meta"><span>v0.7.0</span><span>Private registry</span><span>Security</span></div><section id="access" class="access-callout"><h2>Install the package</h2><p>After WorkRoot approves private registry access, install the release-aligned package:</p><pre><code>bun add @wrnexus/jwt@0.7.0</code><button type="button" class="copy-button" aria-label="Copy installation command">Copy</button></pre><p><a href="/access">Request preview access</a>. Never put registry tokens in source control.</p></section></section><section id="guide"><blockquote>Dependency-free JSON Web Tokens (HS256) via Web Crypto, plus a bearer-token auth middleware for WRNexusJS.</blockquote>
|
||||
<article id="main" class="documentation prose standalone package-document"><nav class="breadcrumbs" aria-label="Breadcrumb"><a href="/">Home</a><span>/</span><a href="/packages">Packages</a><span>/</span><span aria-current="page">@wrnexus/jwt</span></nav><section class="doc-intro"><span class="eyebrow">Security · Package reference</span><h1>@wrnexus/jwt</h1><p>HS256 JWT signing, verification, and bearer authentication.</p><div class="doc-meta"><span>v0.8.0</span><span>Private registry</span><span>Security</span></div><section id="access" class="access-callout"><h2>Install the package</h2><p>After WorkRoot approves private registry access, install the release-aligned package:</p><pre><code>bun add @wrnexus/jwt@0.8.0</code><button type="button" class="copy-button" aria-label="Copy installation command">Copy</button></pre><p><a href="/access">Request preview access</a>. Never put registry tokens in source control.</p></section></section><section id="guide"><blockquote>Dependency-free JSON Web Tokens (HS256) via Web Crypto, plus a bearer-token auth middleware for WRNexusJS.</blockquote>
|
||||
<p>Part of the <strong>WRNexusJS</strong> framework — an SSR-first, Bun-native full-stack web framework.</p>
|
||||
<h3 id="overview">Overview</h3>
|
||||
<p><code>@wrnexus/jwt</code> signs and verifies stateless JSON Web Tokens using the <strong>HS256</strong> (HMAC-SHA-256) algorithm. It has no runtime dependencies — signing and verification are implemented directly on the standard <strong>Web Crypto</strong> API (<code>crypto.subtle</code>), which Bun provides natively. It runs server-side and pairs with the session-based auth in <code>@wrnexus/core</code>, giving you a stateless option for API and mobile clients. Reach for it when you need bearer-token auth rather than cookie sessions.</p>
|
||||
@@ -87,7 +87,46 @@ app.use(jwtAuth({ secret: process.env.JWT_SECRET!, required: false }))
|
||||
<p>are not supported.</p>
|
||||
<li>Integrates with [<code>@wrnexus/core</code>](../core) for <code>Context</code>, <code>Middleware</code>, and</li>
|
||||
<p><code>ctx.user</code>; it complements the framework's cookie/session auth with a stateless bearer-token flow for API and mobile clients.</p>
|
||||
</ul></section><section id="api" class="api"><h2>Complete TypeScript API</h2><p>Generated from the exact installed package declarations.</p><pre data-language="typescript"><code>import { Context, Middleware } from '@wrnexus/core';
|
||||
</ul>
|
||||
<h3 id="access-refresh-scope-and-cookie-helpers">Access, refresh, scope, and cookie helpers</h3>
|
||||
<pre data-language="ts"><code>import {
|
||||
createAccessToken,
|
||||
createRefreshToken,
|
||||
verifyAccessToken,
|
||||
verifyRefreshToken,
|
||||
extractBearerToken,
|
||||
requireScopes,
|
||||
jwtCookie,
|
||||
} from "@wrnexus/jwt";</code></pre>
|
||||
<p>The helpers add explicit <code>type: "access" | "refresh"</code> claims, scope checks, refresh-token family metadata, no-store token responses, and secure cookie defaults. <code>__Host-</code> cookies are rejected unless they use <code>Path=/</code> and <code>Secure</code>; <code>SameSite=None</code> is rejected without <code>Secure</code>.</p>
|
||||
<h3 id="0-8-helper-kit">0.8 helper kit</h3>
|
||||
<pre data-language="ts"><code>import {
|
||||
createTokenPair,
|
||||
verifyAccessToken,
|
||||
verifyRefreshToken,
|
||||
extractBearerToken,
|
||||
readJwtCookie,
|
||||
jwtCookie,
|
||||
clearJwtCookie,
|
||||
requireScopes,
|
||||
} from "@wrnexus/jwt";
|
||||
|
||||
const pair = await createTokenPair(user.id, {
|
||||
accessSecret: process.env.JWT_ACCESS_SECRET!,
|
||||
refreshSecret: process.env.JWT_REFRESH_SECRET!,
|
||||
scopes: ["profile:read"],
|
||||
family: sessionFamily,
|
||||
});</code></pre>
|
||||
<p>The helper kit validates <code>__Host-</code> cookie invariants, cookie names and paths, <code>SameSite=None</code> security, typed access/refresh token types, scope requirements, and no-store token responses. In addition to local HS256 secrets/keyrings, the package verifies standards-based RS256 tokens through bounded remote JWKS caches:</p>
|
||||
<pre data-language="ts"><code>import { createRemoteJwks, verifyJwtWithJwks } from "@wrnexus/jwt";
|
||||
|
||||
const jwks = createRemoteJwks("https://issuer.example/.well-known/jwks.json");
|
||||
const claims = await verifyJwtWithJwks(token, jwks, {
|
||||
issuer: "https://issuer.example",
|
||||
audience: "my-api",
|
||||
maxAge: 300,
|
||||
});</code></pre>
|
||||
<p>JWKS URLs must use HTTPS. Responses have key-count/byte limits, accept only RS256 signing RSA keys, deduplicate concurrent refreshes, cache imported public keys, and force an immediate refresh for an unknown <code>kid</code> so issuer rotation does not wait for cache expiry. Never use decoded-but-unverified claims for an authorization decision.</p></section><section id="api" class="api"><h2>Complete TypeScript API</h2><p>Generated from the exact installed package declarations.</p><pre data-language="typescript"><code>import { Context, Middleware } from '@wrnexus/core';
|
||||
|
||||
interface JwtKey {
|
||||
id: string;
|
||||
@@ -107,6 +146,91 @@ declare function createJwtKeyring(keys: JwtKey[]): JwtKeyring;
|
||||
declare function signWithKeyring(claims: JwtClaims, keyring: JwtKeyring, options?: SignOptions): Promise<string>;
|
||||
declare function verifyWithKeyring<T extends JwtClaims = JwtClaims>(token: string, keyring: JwtKeyring, options?: VerifyOptions): Promise<T>;
|
||||
|
||||
interface AccessTokenClaims extends JwtClaims {
|
||||
sub: string;
|
||||
type: "access";
|
||||
scopes?: string[];
|
||||
}
|
||||
interface RefreshTokenClaims extends JwtClaims {
|
||||
sub: string;
|
||||
type: "refresh";
|
||||
family?: string;
|
||||
}
|
||||
declare function extractBearerToken(value: Headers | Request | Context | string | null | undefined): string | undefined;
|
||||
declare function tryVerifyJwt<T extends JwtClaims = JwtClaims>(token: string | undefined, secret: string, options?: VerifyOptions): Promise<T | null>;
|
||||
declare function assertJwtClaims<T extends JwtClaims>(claims: T, requirements?: {
|
||||
subject?: boolean;
|
||||
type?: string;
|
||||
required?: string[];
|
||||
}): T;
|
||||
declare function tokenScopes(claims: JwtClaims): string[];
|
||||
declare function hasScopes(claims: JwtClaims, required: readonly string[], mode?: "all" | "any"): boolean;
|
||||
declare function requireScopes(required: readonly string[], mode?: "all" | "any"): Middleware;
|
||||
declare function createAccessToken(subject: string, secret: string, options?: Omit<SignOptions, "expiresIn"> & {
|
||||
expiresIn?: number;
|
||||
scopes?: string[];
|
||||
claims?: JwtClaims;
|
||||
}): Promise<string>;
|
||||
declare function createRefreshToken(subject: string, secret: string, options?: Omit<SignOptions, "expiresIn"> & {
|
||||
expiresIn?: number;
|
||||
family?: string;
|
||||
claims?: JwtClaims;
|
||||
}): Promise<string>;
|
||||
declare function verifyAccessToken(token: string, secret: string, options?: VerifyOptions): Promise<AccessTokenClaims>;
|
||||
declare function verifyRefreshToken(token: string, secret: string, options?: VerifyOptions): Promise<RefreshTokenClaims>;
|
||||
declare function readJwtCookie(value: Headers | Request | string | null | undefined, name?: string): string | undefined;
|
||||
declare function jwtCookie(token: string, options?: {
|
||||
name?: string;
|
||||
maxAge?: number;
|
||||
secure?: boolean;
|
||||
sameSite?: "Strict" | "Lax" | "None";
|
||||
path?: string;
|
||||
}): string;
|
||||
declare function clearJwtCookie(options?: Omit<Parameters<typeof jwtCookie>[1], "maxAge">): string;
|
||||
interface JwtTokenPair {
|
||||
accessToken: string;
|
||||
refreshToken: string;
|
||||
tokenType: "Bearer";
|
||||
expiresIn: number;
|
||||
}
|
||||
declare function createTokenPair(subject: string, input: {
|
||||
accessSecret: string;
|
||||
refreshSecret?: string;
|
||||
accessExpiresIn?: number;
|
||||
refreshExpiresIn?: number;
|
||||
scopes?: string[];
|
||||
family?: string;
|
||||
accessOptions?: Omit<SignOptions, "expiresIn">;
|
||||
refreshOptions?: Omit<SignOptions, "expiresIn">;
|
||||
}): Promise<JwtTokenPair>;
|
||||
declare function jwtResponse(accessToken: string, input?: {
|
||||
refreshToken?: string;
|
||||
expiresIn?: number;
|
||||
tokenType?: string;
|
||||
scope?: string[];
|
||||
}): Response;
|
||||
|
||||
interface RemoteJwksOptions {
|
||||
fetch?: typeof fetch;
|
||||
cacheTtlMs?: number;
|
||||
maxKeys?: number;
|
||||
maxBytes?: number;
|
||||
now?: () => number;
|
||||
}
|
||||
interface RemoteJwks {
|
||||
resolve(kid: string, alg: string): Promise<CryptoKey>;
|
||||
refresh(): Promise<void>;
|
||||
clear(): void;
|
||||
stats(): {
|
||||
fetches: number;
|
||||
hits: number;
|
||||
keys: number;
|
||||
expiresAt: number;
|
||||
};
|
||||
}
|
||||
declare function createRemoteJwks(url: string, options?: RemoteJwksOptions): RemoteJwks;
|
||||
declare function verifyJwtWithJwks<T extends JwtClaims = JwtClaims>(token: string, jwks: RemoteJwks, options?: VerifyOptions): Promise<T>;
|
||||
|
||||
/**
|
||||
* @wrnexus/jwt — dependency-free JSON Web Tokens (HS256) via WebCrypto, plus a
|
||||
* bearer-token auth middleware. Pairs with the session auth in @wrnexus/core for
|
||||
@@ -165,7 +289,7 @@ interface JwtAuthOptions {
|
||||
*/
|
||||
declare function jwtAuth(options: JwtAuthOptions): Middleware;
|
||||
|
||||
export { type JwtAuthOptions, type JwtClaims, JwtError, type JwtKey, type JwtKeyring, type SignOptions, type VerifyOptions, createJwtKeyring, decodeJwt, jwtAuth, signJwt, signWithKeyring, verifyJwt, verifyWithKeyring };
|
||||
export { type AccessTokenClaims, type JwtAuthOptions, type JwtClaims, JwtError, type JwtKey, type JwtKeyring, type JwtTokenPair, type RefreshTokenClaims, type RemoteJwks, type RemoteJwksOptions, type SignOptions, type VerifyOptions, assertJwtClaims, clearJwtCookie, createAccessToken, createJwtKeyring, createRefreshToken, createRemoteJwks, createTokenPair, decodeJwt, extractBearerToken, hasScopes, jwtAuth, jwtCookie, jwtResponse, readJwtCookie, requireScopes, signJwt, signWithKeyring, tokenScopes, tryVerifyJwt, verifyAccessToken, verifyJwt, verifyJwtWithJwks, verifyRefreshToken, verifyWithKeyring };
|
||||
</code></pre></section><section id="examples" class="examples"><h2>Examples</h2><p>Copy-ready examples from the installed package documentation.</p><div class="example-grid"><article class="example-card"><h3>Typical usage</h3><pre data-language="ts"><code>import { signJwt, verifyJwt, jwtAuth, JwtError } from "@wrnexus/jwt";
|
||||
|
||||
const secret = process.env.JWT_SECRET!;
|
||||
@@ -190,9 +314,9 @@ app.use(jwtAuth({ secret: process.env.JWT_SECRET! }));
|
||||
|
||||
// Optional auth — populate ctx.user when present, but don't 401
|
||||
app.use(jwtAuth({ secret: process.env.JWT_SECRET!, required: false }));</code></pre></article></div></section></article>
|
||||
<aside class="on-this-page"><h2>On this page</h2><nav><a class="toc-level-2" href="#guide">Guide</a><a class="toc-level-3" href="#overview">Overview</a><a class="toc-level-3" href="#api">API</a><a class="toc-level-4" href="#signjwt-payload-secret-options">signJwt(payload, secret, options?)</a><a class="toc-level-4" href="#verifyjwt-t-token-secret-options">verifyJwt<T>(token, secret, options?)</a><a class="toc-level-4" href="#jwtauth-options">jwtAuth(options)</a><a class="toc-level-3" href="#usage">Usage</a><a class="toc-level-3" href="#requirements-notes">Requirements / Notes</a><a class="toc-level-2" href="#api">Complete API</a><a class="toc-level-2" href="#examples">Examples</a></nav></aside>
|
||||
<aside class="on-this-page"><h2>On this page</h2><nav><a class="toc-level-2" href="#guide">Guide</a><a class="toc-level-3" href="#overview">Overview</a><a class="toc-level-3" href="#api">API</a><a class="toc-level-4" href="#signjwt-payload-secret-options">signJwt(payload, secret, options?)</a><a class="toc-level-4" href="#verifyjwt-t-token-secret-options">verifyJwt<T>(token, secret, options?)</a><a class="toc-level-4" href="#jwtauth-options">jwtAuth(options)</a><a class="toc-level-3" href="#usage">Usage</a><a class="toc-level-3" href="#requirements-notes">Requirements / Notes</a><a class="toc-level-3" href="#access-refresh-scope-and-cookie-helpers">Access, refresh, scope, and cookie helpers</a><a class="toc-level-3" href="#0-8-helper-kit">0.8 helper kit</a><a class="toc-level-2" href="#api">Complete API</a><a class="toc-level-2" href="#examples">Examples</a></nav></aside>
|
||||
</main>
|
||||
<footer><div class="footer-brand"><span class="footer-mark" aria-hidden="true">W</span><p><strong>WRNexusJS 0.7.0</strong><span>Complete API documentation generated from installed package declarations.</span></p></div><nav aria-label="Footer"><a href="/packages">All packages</a><a href="/getting-started">Get started</a><a href="/security">Security</a><a href="/support">Support</a><a href="/llms.txt">AI guide</a></nav><p class="footer-meta">Private Developer Preview · Bun-native</p></footer>
|
||||
<footer><div class="footer-brand"><span class="footer-mark" aria-hidden="true">W</span><p><strong>WRNexusJS 0.8.0</strong><span>Complete API documentation generated from installed package declarations.</span></p></div><nav aria-label="Footer"><a href="/packages">All packages</a><a href="/getting-started">Get started</a><a href="/security">Security</a><a href="/support">Support</a><a href="/llms.txt">AI guide</a></nav><p class="footer-meta">Private Developer Preview · Bun-native</p></footer>
|
||||
<BackToTop />
|
||||
</div>
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user