jwk
js/security/jwk.ts
fino:security/jwk - JSON Web Key generation, import, export, and selection.
JSON Web Key specification: https://www.rfc-editor.org/rfc/rfc7517
Use this module when JOSE helpers need keys in JWK or JWKS form. It can
generate symmetric, RSA, and EC keys, import JWKs into WebCrypto keys,
export public key material, compute RFC 7638 thumbprints, and select keys
from a key set by kid, alg, kty, and use.
Private JWK fields and symmetric k values are secret material. Keep them
out of logs and client responses. For public discovery endpoints, export or
publish only public JWK fields.
import {
generateJwk,
exportPublicJwk,
jwkThumbprint,
} from 'fino:security/jwk';
const privateKey = await generateJwk({ kty: 'RSA', alg: 'RS256', kid: 'signing-1' });
const publicKey = await exportPublicJwk(privateKey);
const thumbprint = await jwkThumbprint(publicKey);
Types
type JsonWebKeyLike = Record<string, unknown>
JSON Web Key object accepted by the security helpers.
The map follows the JOSE JWK shape and may contain public, private, or
symmetric key material depending on kty. Callers are responsible for
keeping private fields such as d and symmetric k values secret.
import type { JsonWebKeyLike } from 'fino:security/jwk';
const key: JsonWebKeyLike = { kty: 'oct', k: 'base64url-secret', alg: 'HS256' };
Interfaces
interface JsonWebKeySet {
JSON Web Key Set container.
The keys array is searched in order by selectJwk() and JWT/JWE helpers.
Use kid values when multiple keys can validate the same algorithm.
import type { JsonWebKeySet } from 'fino:security/jwk';
const jwks: JsonWebKeySet = { keys: [{ kty: 'oct', k: 'base64url-secret', kid: 'current' }] };
Properties
keys: JsonWebKeyLike[]
Keys included in the set.
Selection returns the first matching key. Empty arrays are valid but cannot satisfy a selector.
import type { JsonWebKeySet } from 'fino:security/jwk';
const jwks: JsonWebKeySet = { keys: [] };
interface GenerateJwkOptions {
Options for generating symmetric, RSA, or EC JSON Web Keys.
Defaults depend on kty: oct uses a 256-bit HMAC key, RSA uses a
2048-bit modulus, and EC uses P-256. Generated keys are extractable so
they can be returned as JWK objects; protect private or symmetric output.
import type { GenerateJwkOptions } from 'fino:security/jwk';
const options: GenerateJwkOptions = { kty: 'RSA', alg: 'RS256', kid: 'signing-1' };
Properties
kty: 'oct' | 'RSA' | 'EC'
Key type to generate.
Use oct for shared secrets, RSA for RSA signatures or RSA-OAEP, and
EC for ECDSA. Unsupported values are rejected by the type and runtime
algorithm selection.
import type { GenerateJwkOptions } from 'fino:security/jwk';
const options: GenerateJwkOptions = { kty: 'oct' };
alg?: string
Optional JOSE algorithm identifier.
The algorithm influences hash selection and generated key usages. If omitted, helpers choose defaults such as SHA-256 based on key type.
import type { GenerateJwkOptions } from 'fino:security/jwk';
const options: GenerateJwkOptions = { kty: 'EC', alg: 'ES256' };
kid?: string
Optional key identifier copied into the generated JWK.
Use stable kid values for rotation and JWKS selection.
import type { GenerateJwkOptions } from 'fino:security/jwk';
const options: GenerateJwkOptions = { kty: 'RSA', kid: '2026-06' };
use?: string
Optional JWK use value.
Common values include sig and enc. The helper copies it without
validation.
import type { GenerateJwkOptions } from 'fino:security/jwk';
const options: GenerateJwkOptions = { kty: 'RSA', use: 'sig' };
key_ops?: string[]
Optional JWK key_ops list.
The list is copied into the returned JWK. WebCrypto generation usages are
still inferred from kty and alg.
import type { GenerateJwkOptions } from 'fino:security/jwk';
const options: GenerateJwkOptions = { kty: 'oct', key_ops: ['sign', 'verify'] };
length?: number
Symmetric key length in bits for oct keys.
Defaults to 256. The value is divided by 8 to generate random key bytes.
import type { GenerateJwkOptions } from 'fino:security/jwk';
const options: GenerateJwkOptions = { kty: 'oct', length: 512 };
namedCurve?: 'P-256' | 'P-384' | 'P-521'
Named curve for EC keys.
Defaults to P-256. It is ignored for non-EC key generation.
import type { GenerateJwkOptions } from 'fino:security/jwk';
const options: GenerateJwkOptions = { kty: 'EC', namedCurve: 'P-384' };
modulusLength?: number
RSA modulus length in bits.
Defaults to 2048. Larger values increase signing and decryption cost.
import type { GenerateJwkOptions } from 'fino:security/jwk';
const options: GenerateJwkOptions = { kty: 'RSA', modulusLength: 3072 };
interface JwkSelector {
Criteria used to select a key from a JWKS or key array.
All supplied fields must match. Missing fields on a candidate are permissive
for alg, use, and key_ops, so include kid when exact key selection is
important.
import type { JwkSelector } from 'fino:security/jwk';
const selector: JwkSelector = { kid: 'current', alg: 'RS256' };
Properties
kid?: string
Required key identifier.
When supplied, candidate keys must have the same kid.
import type { JwkSelector } from 'fino:security/jwk';
const selector: JwkSelector = { kid: 'current' };
alg?: string
Required algorithm when the candidate declares alg.
Keys without an alg field are allowed to match, which supports generic
keys in a JWKS.
import type { JwkSelector } from 'fino:security/jwk';
const selector: JwkSelector = { alg: 'HS256' };
kty?: string
Required JWK key type.
Use it to distinguish symmetric, RSA, and EC keys in mixed sets.
import type { JwkSelector } from 'fino:security/jwk';
const selector: JwkSelector = { kty: 'RSA' };
use?: string
Required JWK use value when the candidate declares use.
Keys without use are allowed to match.
import type { JwkSelector } from 'fino:security/jwk';
const selector: JwkSelector = { use: 'sig' };
key_ops?: string[]
Required key operations when the candidate declares key_ops.
Every requested operation must be present in the candidate list. Keys
without key_ops are allowed to match.
import type { JwkSelector } from 'fino:security/jwk';
const selector: JwkSelector = { key_ops: ['verify'] };
Functions
async function generateJwk(options: GenerateJwkOptions): Promise<JsonWebKeyLike>
Generate an extractable JSON Web Key using the runtime crypto backend.
For oct keys the helper returns random key bytes directly as a symmetric
JWK. For RSA and EC keys it generates a WebCrypto key pair and exports the
private key JWK, including private fields. Unsupported key options or crypto
backend failures reject the promise.
import { generateJwk } from 'fino:security/jwk';
const key = await generateJwk({ kty: 'RSA', alg: 'RS256', kid: 'signing-1' });
async function importJwk(jwk: JsonWebKeyLike, usages: string[] = []): Promise<CryptoKey>
Import a JWK as a WebCrypto CryptoKey for the requested usages.
The algorithm is inferred from kty, alg, and requested usages. The
returned key is extractable. Unsupported key types, malformed JWK fields, or
incompatible usages reject the promise.
import { generateJwk, importJwk } from 'fino:security/jwk';
const jwk = await generateJwk({ kty: 'oct', alg: 'HS256' });
const key = await importJwk(jwk, ['sign']);
async function exportPublicJwk(key: JsonWebKeyLike | CryptoKey): Promise<JsonWebKeyLike>
Export a public JWK from a JWK or CryptoKey.
Private RSA/EC fields and symmetric k material are removed from the
returned object. Passing a symmetric JWK therefore returns metadata without
usable key bytes. Crypto export failures reject the promise.
import { exportPublicJwk, generateJwk } from 'fino:security/jwk';
const privateJwk = await generateJwk({ kty: 'RSA', alg: 'RS256' });
const publicJwk = await exportPublicJwk(privateJwk);
async function jwkThumbprint(jwk: JsonWebKeyLike): Promise<string>
Compute an RFC 7638 SHA-256 thumbprint for a JWK-like object.
The helper canonicalizes only the required public members for supported key
types: RSA uses e, kty, and n; EC uses crv, kty, x, and y; and
oct uses k and kty. Private fields and metadata such as kid, use,
key_ops, and alg are intentionally ignored. Missing required members or
unsupported kty values throw.
import { generateJwk, jwkThumbprint } from 'fino:security/jwk';
const jwk = await generateJwk({ kty: 'oct' });
const thumbprint = await jwkThumbprint(jwk);
function selectJwk(
jwks: JsonWebKeySet | JsonWebKeyLike[],
selector: JwkSelector
): JsonWebKeyLike | undefined
Select the first matching key from a JWKS or key array.
Returns undefined when no candidate satisfies the selector. The search is
order-preserving, so put the preferred or current key first when several keys
could match. Candidate keys that omit alg, use, or key_ops are treated
as generic keys for that field and may match a selector that requests it.
import { selectJwk } from 'fino:security/jwk';
const key = selectJwk({ keys: [{ kid: 'current', kty: 'oct' }] }, { kid: 'current' });
function jwkFromSecret(secret: string | Uint8Array, alg = 'HS256', kid?: string): JsonWebKeyLike
Build an oct JWK from a shared secret for HMAC or direct encryption use.
String secrets are encoded as UTF-8 before base64url storage. The default
algorithm is HS256; pass dir, A128GCM, or A256GCM for direct JWE/AES
use when the secret length matches that algorithm's needs.
import { jwkFromSecret } from 'fino:security/jwk';
const jwk = jwkFromSecret('shared-secret', 'HS256', 'signing-1');