unjwt Skill
Low-level JWT library using the Web Crypto API. Zero runtime dependencies for core; optional peer deps for framework adapters.
Implements JWS (RFC 7515), JWE (RFC 7516), and JWK (RFC 7517).
Quick orientation
Skill written against
unjwt@0.7.2. APIs are stable within v0.7 but check the changelog if behaviour seems off on a newer version.
The following is a list of reference files:
references/jws.md:sign(),verify(),signMulti(),verifyMulti(),verifyMultiAll(),generalToFlattenedJWS(),JWSSignOptions,JWSVerifyOptions,JWSMultiSignOptions,JWSMultiVerifyOptions,JWSMultiVerifyAllOptions,JWSMultiVerifyOutcome,JWSGeneralSerialization,JWSFlattenedSerialization,JWSMultiSignerreferences/jwe.md:encrypt(),decrypt(),encryptMulti(),decryptMulti(),generalToFlattened(),JWEEncryptOptions,JWEDecryptOptions,JWEMultiEncryptOptions,JWEMultiDecryptOptions,JWEGeneralSerialization,JWEFlattenedSerialization,JWEMultiRecipientreferences/jwk.md:generateKey(),generateJWK(),importKey(),exportKey(),wrapKey(),unwrapKey(),deriveSharedSecret(), PEM import/export (importPEM,exportPEM;importFromPEM,exportToPEMare deprecated aliases), PBES2 key derivation (deriveKeyFromPassword,deriveJWKFromPassword), JWK set utilities (getJWKsFromSet,getJWKFromSet— deprecated), JWK cache (configureJWKCache,clearJWKCache,WeakMapJWKCache), key lookup types (JWKLookupFunction,JWKLookupFunctionHeader), all JWK type definitionsreferences/utils.md:base64UrlEncode/base64UrlDecode,base64Encode/base64Decode,secureRandomBytes,concatUint8Arrays,textEncoder/textDecoder, type guards (isJWK,isJWKSet,isSymmetricJWK,isAsymmetricJWK,isPrivateJWK,isPublicJWK,isCryptoKey,isCryptoKeyPair,assertCryptoKey),validateJwtClaims,inferJWSAllowedAlgorithms,inferJWEAllowedAlgorithms,computeDurationInSeconds,Durationformat (aliased byExpiresIn/NotBeforeIn/MaxTokenAge),JWTClaimValidationOptionsreferences/adapters-h3.md: H3 session adapters (v1 and v2),useJWESession,useJWSSession,SessionManagerinterface,SessionConfigJWE,SessionConfigJWS, lifecycle hooks (onRead,onUpdate,onClear,onExpire,onError), key lookup hooks (onUnsealKeyLookup,onVerifyKeyLookup), lower-level functions, cookie chunking (v2), header-based tokens, refresh token patternreferences/adapters-elysia.md: Elysia session adapter,jwsSession/jweSessionplugins, ambientctx[contextKey],requireSessionguard macro (derived percontextKey), multiple sessions (access JWS + refresh JWE),createJWSSession/createJWESessionlower-level,SessionConfigJWS/SessionConfigJWE, lifecycle hooks (contextnotevent), cookie chunking, header tokens,isolatedDeclarationsplugin typing
Export Paths
| Path | Purpose |
|---|---|
unjwt |
Flat barrel: all public functions and types from jws, jwe, jwk, utils |
unjwt/jws |
sign(), verify() (Compact) — signMulti(), verifyMulti() (General JSON Serialization) |
unjwt/jwe |
encrypt(), decrypt() (Compact) — encryptMulti(), decryptMulti() (General JSON Serialization) |
unjwt/jwk |
Key generation, import/export, wrap/unwrap, PEM conversion, PBES2, cache utils |
unjwt/utils |
Base64URL encode/decode, type guards, JWT claim validation, secureRandomBytes |
unjwt/adapters/h3 |
H3 session adapter (aliases h3v1) |
unjwt/adapters/h3v1 |
H3 v1 session adapter (Nuxt v4, Nitro v2) |
unjwt/adapters/h3v2 |
H3 v2 session adapter (Nuxt v5, Nitro v3) |
unjwt/adapters/elysia |
Elysia session adapter — jwsSession/jweSession plugins (>=1.4.0) |
Quick Start
// Sign and verify (JWS)
import { sign, verify } from "unjwt/jws";
import { generateJWK } from "unjwt/jwk";
const key = await generateJWK("HS256");
const token = await sign({ sub: "user123" }, key, { expiresIn: "1h" });
const { payload } = await verify(token, key);
// Encrypt and decrypt (JWE)
import { encrypt, decrypt } from "unjwt/jwe";
const jwe = await encrypt({ secret: "data" }, "password");
const { payload } = await decrypt(jwe, "password");
// H3 session
import { useJWESession } from "unjwt/adapters/h3v2";
const session = await useJWESession(event, { key: "secret", maxAge: "7D" });
await session.update({ userId: "123" });
Key Concepts
JOSEPayload: the payload type accepted bysign/encrypt—string | Uint8Array | Record<string, unknown>; covers both JWT and generic serializable objects.JWTClaimsremains the spec-compliant sub-type for typed claim access- JWK-first key model: functions accept JWK objects directly;
importKey()normalizes CryptoKey/JWK/Uint8Array/string - Algorithm inference:
sign/encryptinferalg/encfrom JWK properties when not explicitly provided; password strings default to PBES2 dir(direct encryption): pass aCryptoKey | JWK_oct | Uint8Arraydirectly as the CEK;encmust always be specified- Multi-recipient JWE:
encryptMulti()emits General JSON Serialization (RFC 7516 §7.2.1). One shared CEK, one ciphertext, per-recipient wraps.dirand bareECDH-ESare rejected in multi (throwERR_JWE_ALG_FORBIDDEN_IN_MULTI).decryptMulti()accepts General + Flattened (auto-normalized); compact tokens stay withdecrypt() - Multi-signature JWS:
signMulti()emits General JSON Serialization (RFC 7515 §7.2.1). Shared payload, per-signer protected header.b64: false(RFC 7797) must be consistent across all signers.verifyMulti()returns the first valid signature;verifyMultiAll()returns per-signer outcomes for policy-driven verification (all-must-verify, M-of-N quorum, named signers). Both accept General + Flattened (auto-normalized); compact tokens stay withverify() - ExpiresIn: time durations accept numbers (seconds) or strings:
"30s","10m","2h","7D","1W","3M","1Y"(also long forms:"minutes","hours","days","weeks","months","years") - H3 Session Adapters: store JWTs in chunked cookies; sessions are lazy (
idisundefineduntilupdate()is called) - PBES2 security: default
p2c(iteration count) is600_000per OWASP cookbook; only lower it for legacy interoperability
Source: sandros94/unjwt — distributed by TomeVault.