{"id":27946257,"url":"https://github.com/sandros94/unjwt","last_synced_at":"2025-05-07T13:49:30.640Z","repository":{"id":289583929,"uuid":"968138062","full_name":"sandros94/unjwt","owner":"sandros94","description":"A collection of low-level JWT utilities using the Web Crypto API.","archived":false,"fork":false,"pushed_at":"2025-05-04T21:44:15.000Z","size":365,"stargazers_count":3,"open_issues_count":2,"forks_count":0,"subscribers_count":1,"default_branch":"main","last_synced_at":"2025-05-04T22:33:50.567Z","etag":null,"topics":["jwt","webcrypto","webcrypto-api"],"latest_commit_sha":null,"homepage":"https://www.npmjs.com/package/unjwt","language":"TypeScript","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/sandros94.png","metadata":{"files":{"readme":"README.md","changelog":"CHANGELOG.md","contributing":null,"funding":".github/FUNDING.yaml","license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null,"zenodo":null},"funding":{"github":["sandros94"],"patreon":null,"open_collective":null,"ko_fi":null,"tidelift":null,"community_bridge":null,"liberapay":null,"issuehunt":null,"otechie":null,"lfx_crowdfunding":null,"custom":null}},"created_at":"2025-04-17T15:12:47.000Z","updated_at":"2025-04-28T18:29:16.000Z","dependencies_parsed_at":"2025-04-24T02:43:04.206Z","dependency_job_id":"5746a0e7-5b20-4c55-901c-2cb205a670f7","html_url":"https://github.com/sandros94/unjwt","commit_stats":null,"previous_names":["sandros94/unjwt"],"tags_count":1,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/sandros94%2Funjwt","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/sandros94%2Funjwt/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/sandros94%2Funjwt/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/sandros94%2Funjwt/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/sandros94","download_url":"https://codeload.github.com/sandros94/unjwt/tar.gz/refs/heads/main","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":252891416,"owners_count":21820529,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["jwt","webcrypto","webcrypto-api"],"created_at":"2025-05-07T13:49:30.140Z","updated_at":"2025-05-07T13:49:30.631Z","avatar_url":"https://github.com/sandros94.png","language":"TypeScript","readme":"# unjwt\n\n\u003c!-- automd:badges bundlephobia style=\"flat\" color=\"FFDC3B\" --\u003e\n\n[![npm version](https://img.shields.io/npm/v/unjwt?color=FFDC3B)](https://npmjs.com/package/unjwt)\n[![npm downloads](https://img.shields.io/npm/dm/unjwt?color=FFDC3B)](https://npm.chart.dev/unjwt)\n[![bundle size](https://img.shields.io/bundlephobia/minzip/unjwt?color=FFDC3B)](https://bundlephobia.com/package/unjwt)\n\n\u003c!-- /automd --\u003e\n\nA collection of low-level JWT ([RFC 7519](https://datatracker.ietf.org/doc/html/rfc7519)) utilities using the Web Crypto API. Supports:\n\n- **JWS (JSON Web Signature, [RFC 7515](https://datatracker.ietf.org/doc/html/rfc7515))**: sign and verify tokens using HMAC, RSA (RSASSA-PKCS1-v1_5 \u0026 RSA-PSS), and ECDSA algorithms.\n- **JWE (JSON Web Encryption, [RFC 7516](https://datatracker.ietf.org/doc/html/rfc7516))**: encrypt and decrypt data using various key management algorithms (AES Key Wrap, AES-GCM Key Wrap, RSA-OAEP, PBES2, ECDH-ES) and content encryption algorithms (AES-GCM, AES-CBC HMAC-SHA2).\n- **JWK (JSON Web Key, [RFC 7517](https://datatracker.ietf.org/doc/html/rfc7517))**: generate, import, export, wrap, and unwrap keys in JWK format or as `CryptoKey` objects.\n\n## Usage\n\nInstall the package:\n\n```sh\n# ✨ Auto-detect (supports npm, yarn, pnpm, deno and bun)\nnpx nypm install unjwt\n```\n\nImport:\n\n**ESM** (Node.js, Bun, Deno)\n\n```js\nimport { jws, jwe, jwk } from \"unjwt\";\n// JWS functions\nimport { sign, verify } from \"unjwt/jws\";\n// JWE functions\nimport { encrypt, decrypt } from \"unjwt/jwe\";\n// JWK functions\nimport {\n  generateKey,\n  deriveKeyFromPassword,\n  importKey,\n  exportKey,\n  wrapKey,\n  unwrapKey,\n} from \"unjwt/jwk\";\n// Utility functions\nimport { base64UrlEncode, base64UrlDecode, randomBytes } from \"unjwt/utils\";\n```\n\n**CDN** (Deno, Bun and Browsers)\n\n```js\nimport { jws, jwe, jwk } from \"https://esm.sh/unjwt\";\n// JWS functions\nimport { sign, verify } from \"https://esm.sh/unjwt/jws\";\n// JWE functions\nimport { encrypt, decrypt } from \"https://esm.sh/unjwt/jwe\";\n// JWK functions\nimport {\n  generateKey,\n  deriveKeyFromPassword,\n  importKey,\n  exportKey,\n  wrapKey,\n  unwrapKey,\n} from \"https://esm.sh/unjwt/jwk\";\n// Utility functions\nimport {\n  base64UrlEncode,\n  base64UrlDecode,\n  randomBytes,\n} from \"https://esm.sh/unjwt/utils\";\n```\n\n### JWS (JSON Web Signature, [RFC 7515](https://datatracker.ietf.org/doc/html/rfc7515))\n\nFunctions to sign and verify data according to the JWS specification.\n\n#### `sign(payload, key, options)`\n\nCreates a JWS token.\n\n- `payload`: The data to sign (`string`, `Uint8Array`, or a JSON-serializable `object`).\n- `key`: The signing key (`CryptoKey`, `JWK`, or `Uint8Array` for symmetric keys).\n- `options`:\n  - `alg`: (Required) The JWS algorithm (e.g., `\"HS256\"`, `\"RS256\"`, `\"ES256\"`, `\"PS256\"`).\n  - `protectedHeader`: An object for additional JWS Protected Header parameters (e.g., `kid`, `typ`, `cty`, `crit`, `b64`). If `payload` is an object and `typ` is not set, it defaults to `\"JWT\"`. The `b64` parameter ([RFC7797 section-3](https://datatracker.ietf.org/doc/html/rfc7797#section-3)) controls payload encoding (defaults to `true`, meaning Base64URL encoded).\n\nReturns a `Promise\u003cstring\u003e` resolving to the JWS token in Compact Serialization format.\n\n**Example (HS256 with string secret):**\n\n```ts\nimport { sign } from \"unjwt/jws\";\n\nconst payload = { message: \"My important data\" }; // Object payload\nconst secret = \"supersecretkey\"; // String secret, will be imported (length depends on choosen alg)\n\nconst token = await sign(payload, secret, { alg: \"HS256\" });\n\nconsole.log(token);\n// eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9...\n```\n\n**Example (RS256 with CryptoKey):**\n\n```ts\nimport { sign } from \"unjwt/jws\";\nimport { generateKey } from \"unjwt/jwk\";\n\nconst payload = { userId: 123, permissions: [\"read\"] };\nconst { privateKey } = await generateKey(\"RS256\"); // Generates a CryptoKeyPair\n\nconst token = await sign(payload, privateKey, { alg: \"RS256\" });\n\nconsole.log(token);\n// eyJhbGciOiJSUzI1NiIsInR5cCI6IkpXVCJ9...\n```\n\n#### `verify(jws, key, options?)`\n\nVerifies a JWS token.\n\n- `jws`: The JWS token string.\n- `key`: The verification key (`CryptoKey`, `JWK`, `Uint8Array`, or a `KeyLookupFunction`).\n  A `KeyLookupFunction` has the signature `(header: JWSProtectedHeader) =\u003e Promise\u003cCryptoKey | JWK | Uint8Array\u003e | CryptoKey | JWK | Uint8Array`.\n- `options` (optional):\n  - `algorithms`: An array of allowed JWS `alg` values. If not provided, the `alg` from the JWS header is used.\n  - `critical`: An array of JWS header parameter names that the application understands and processes.\n\nReturns a `Promise\u003cJWSVerifyResult\u003cT\u003e\u003e` which is an object `{ payload: T, protectedHeader: JWSProtectedHeader }`.\nThe `payload` type `T` can be `JWTClaims` (object), `string`, or `Uint8Array` depending on the JWS content and headers.\n\n**Example (HS256):**\n\n```ts\nimport { verify } from \"unjwt/jws\";\n\nconst token = \"eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9...\"; // From HS256 sign example\nconst secret = \"supersecretkey\";\n\nconst { payload, protectedHeader } = await verify(token, secret);\nconsole.log(payload); // { message: \"My important data\" }\nconsole.log(protectedHeader); // { alg: \"HS256\", typ: \"JWT\" }\n```\n\n**Example (RS256 with key lookup):**\n\n```ts\nimport { verify } from \"unjwt/jws\";\nimport { generateKey } from \"unjwt/jwk\";\n\nconst token = \"eyJhbGciOiJSUzI1NiIsInR5cCI6IkpXVCJ9...\"; // From RS256 sign example\n\n// Example: using a key lookup function\nconst { publicKey: rsaPublicKey } = await generateKey(\"RS256\"); // For example purposes, assume publicKey is stored/fetched during lookup\n\nconst keyLookup = async (header) =\u003e {\n  if (header.alg === \"RS256\" /* \u0026\u0026 header.kid === 'expected-kid' */) {\n    return rsaPublicKey;\n  }\n  throw new Error(\"Unsupported algorithm or key not found\");\n};\n\nconst { payload } = await verify(token, keyLookup, { algorithms: [\"RS256\"] });\nconsole.log(payload); // { userId: 123, permissions: [\"read\"] }\n```\n\n### JWE (JSON Web Encryption, [RFC 7516](https://datatracker.ietf.org/doc/html/rfc7516))\n\nFunctions to encrypt and decrypt data according to the JWE specification.\n\n#### `encrypt(payload, key, options)`\n\nEncrypts data to produce a JWE token.\n\n- `payload`: The data to encrypt (`string`, `Uint8Array`, or a JSON-serializable `object`).\n- `key`: The Key Encryption Key (KEK) or password (`CryptoKey`, `JWK`, `string`, or `Uint8Array`).\n- `options`:\n  - `alg`: (Required) The JWE Key Management algorithm (e.g., `\"A128KW\"`, `\"RSA-OAEP-256\"`, `\"PBES2-HS256+A128KW\"`, `\"ECDH-ES+A128KW\"`), defaults depends on the key provided.\n  - `enc`: (Required) The JWE Content Encryption algorithm (e.g., `\"A128GCM\"`, `\"A256CBC-HS512\"`), defaults depends on the key provided.\n  - `protectedHeader`: An object for JWE Protected Header parameters (e.g., `kid`, `typ`, `cty`, `crit`, `apu`, `apv`, `p2s`, `p2c`). If `payload` is an object and `typ` is not set, it defaults to `\"JWT\"`.\n  - `cek`: (Optional) Provide your own Content Encryption Key (`CryptoKey` or `Uint8Array`).\n  - `contentEncryptionIV`: (Optional) Provide your own Initialization Vector for content encryption (`Uint8Array`).\n  - Other algorithm-specific options like `p2s`, `p2c` (for PBES2), `keyManagementIV`, `ecdhPartyUInfo`, `ecdhPartyVInfo`.\n\nReturns a `Promise\u003cstring\u003e` resolving to the JWE token in Compact Serialization format.\n\n**Example (PBES2 password-based encryption):**\n\n```ts\nimport { encrypt } from \"unjwt/jwe\";\n\nconst plaintext = \"Secret message for password protection\";\nconst password = \"myVeryStrongPassword123!\";\n\n// Fallback to PBES2-HS256+A128KW and A128GCM if no `alg` and `end` are provided\nconst jweToken = await encrypt(plaintext, password);\nconsole.log(jweToken);\n// JWE token string...\n```\n\n**Example (A128KW with A128GCM):**\n\n```ts\nimport { encrypt } from \"unjwt/jwe\";\nimport { generateKey } from \"unjwt/jwk\";\n\nconst payload = { data: \"sensitive information\" };\nconst kek = await generateKey(\"A128KW\"); // AES Key Wrap key\n\nconst jweToken = await encrypt(payload, kek, {\n  alg: \"A128KW\",\n  enc: \"A128GCM\",\n  protectedHeader: { kid: \"aes-key-1\" },\n});\n\nconsole.log(jweToken);\n// eyJhbGciOiJBMTI4S1ciLCJlbmMiOiJBMTI4R0NNIiwia2lkIjoiYWVzLWtleS0xIn0...\n```\n\n#### `decrypt(jwe, key, options?)`\n\nDecrypts a JWE token.\n\n- `jwe`: The JWE token string.\n- `key`: The Key Decryption Key (KDK) or password (`CryptoKey`, `JWK`, `string`, `Uint8Array`, or a `JWEKeyLookupFunction`).\n  A `JWEKeyLookupFunction` has the signature `(header: JWEHeaderParameters) =\u003e Promise\u003cCryptoKey | JWK | string | Uint8Array\u003e | CryptoKey | JWK | string | Uint8Array`.\n- `options` (optional):\n  - `algorithms`: Array of allowed JWE Key Management `alg` values.\n  - `encryptionAlgorithms`: Array of allowed JWE Content Encryption `enc` values.\n  - `critical`: Array of JWE header parameter names that the application understands.\n  - `unwrappedKeyAlgorithm`: (For `unwrapKey` internally) Algorithm details for the CEK after unwrapping.\n  - `keyUsage`: (For `unwrapKey` internally) Intended usages for the unwrapped CEK.\n\nReturns a `Promise\u003cJWEDecryptResult\u003cT\u003e\u003e` which is an object `{ payload: T, protectedHeader: JWEHeaderParameters, cek: Uint8Array, aad: Uint8Array }`.\nThe `payload` type `T` can be `JWTClaims` (object) or `string`.\n\n**Example (PBES2 password-based decryption):**\n\n```ts\nimport { decrypt } from \"unjwt/jwe\";\n// const jweToken = ...; // From PBES2 encrypt example\n// const password = \"myVeryStrongPassword123!\";\n\nconst { payload } = await decrypt(jweToken, password);\n```\n\n**Example (A128KW with A128GCM):**\n\n```ts\nimport { decrypt } from \"unjwt/jwe\";\n// const jweToken = \"eyJhbGciOiJBMTI4S1ciLCJlbmMiOiJBMTI4R0NNIiwia2lkIjoiYWVzLWtleS0xIn0...\";\n// const kek = ...; // The same AES Key Wrap key used for encryption\n\nasync function decryptData(jweToken: string, kek: CryptoKey) {\n  try {\n    const { payload, protectedHeader, cek } = await decrypt(jweToken, kek, {\n      algorithms: [\"A128KW\"],\n      encryptionAlgorithms: [\"A128GCM\"],\n    });\n    console.log(\"Decrypted Plaintext:\", payload);\n    console.log(\"Protected Header:\", protectedHeader);\n    // console.log(\"CEK (Content Encryption Key):\", cek);\n  } catch (error) {\n    console.error(\"Decryption failed:\", error);\n  }\n}\n```\n\n### JWK (JSON Web Key, [RFC 7517](https://datatracker.ietf.org/doc/html/rfc7517))\n\nUtilities for working with JSON Web Keys.\n\n#### `generateKey(alg, options?)`\n\nGenerates a cryptographic key.\n\n- `alg`: The JWA algorithm identifier for the key to be generated (e.g., `\"HS256\"`, `\"RS256\"`, `\"ES256\"`, `\"A128KW\"`, `\"A128GCM\"`, `\"A128CBC-HS256\"`).\n- `options` (optional):\n  - `toJWK`: If `true`, returns the key(s) in JWK format. Otherwise, returns `CryptoKey`(s) or `Uint8Array` (for composite keys like AES-CBC-HS\\*). Default `false`.\n  - `extractable`: Boolean, whether the generated `CryptoKey` can be exported. Default `true`.\n  - `keyUsage`: Array of `KeyUsage` strings. Defaults are algorithm-specific.\n  - `modulusLength`: For RSA keys (e.g., `2048`, `4096`). Default `2048`.\n  - `publicExponent`: For RSA keys. Default `new Uint8Array([0x01, 0x00, 0x01])`.\n\nReturns a `Promise` resolving to `CryptoKey`, `CryptoKeyPair`, `Uint8Array` (for composite keys), `JWK`, or `{ privateKey: JWK, publicKey: JWK }` depending on `alg` and `options.toJWK`.\n\n**Examples:**\n\n```ts\nimport { generateKey } from \"unjwt/jwk\";\n\n// Generate an HS256 CryptoKey\nconst hmacKey = await generateKey(\"HS256\");\nconsole.log(hmacKey); // CryptoKey\n\n// Generate an RS256 CryptoKeyPair\nconst rsaKeyPair = await generateKey(\"RS256\", { modulusLength: 2048 });\nconsole.log(rsaKeyPair.publicKey); // CryptoKey\nconsole.log(rsaKeyPair.privateKey); // CryptoKey\n\n// Generate an ES384 key pair as JWKs\nconst ecJwks = await generateKey(\"ES384\", { toJWK: true });\nconsole.log(ecJwks.publicKey); // JWK\nconsole.log(ecJwks.privateKey); // JWK\n\n// Generate a composite key for A128CBC-HS256 as Uint8Array\nconst aesCbcHsKeyBytes = await generateKey(\"A128CBC-HS256\");\nconsole.log(aesCbcHsKeyBytes); // Uint8Array (32 bytes: 16 for AES, 16 for HMAC)\n\n// Generate an A256GCM key as a JWK\nconst aesGcmJwk = await generateKey(\"A256GCM\", { toJWK: true });\nconsole.log(aesGcmJwk); // JWK\n```\n\n#### `deriveKeyFromPassword(password, alg, options)`\n\nDerives a key from a password using PBKDF2 for PBES2 algorithms.\n\n- `password`: The password (`string` or `Uint8Array`).\n- `alg`: The PBES2 algorithm (e.g., `\"PBES2-HS256+A128KW\"`).\n- `options`:\n  - `salt`: The salt (`Uint8Array`, at least 8 octets).\n  - `iterations`: The iteration count (positive integer).\n  - `toJWK`: If `true`, returns a `JWK_oct`. Otherwise, `CryptoKey`. Default `false`.\n  - `extractable`: Boolean for `CryptoKey`. Default `false` unless `toJWK` is true.\n  - `keyUsage`: For `CryptoKey`. Default `[\"wrapKey\", \"unwrapKey\"]`.\n\nReturns a `Promise` resolving to `CryptoKey` or `JWK_oct`.\n\n**Example:**\n\n```ts\nimport { deriveKeyFromPassword } from \"unjwt/jwk\";\nimport { randomBytes, textEncoder } from \"unjwt/utils\";\n\nconst password = \"mySecretPassword\";\nconst salt = randomBytes(16);\nconst iterations = 4096;\n\nconst derivedKey = await deriveKeyFromPassword(password, \"PBES2-HS384+A192KW\", {\n  salt,\n  iterations,\n});\nconsole.log(derivedKey); // CryptoKey for AES-KW (192-bit)\n\nconst derivedJwk = await deriveKeyFromPassword(password, \"PBES2-HS512+A256KW\", {\n  salt,\n  iterations,\n  toJWK: true,\n});\nconsole.log(derivedJwk); // JWK_oct { kty: \"oct\", k: \"...\", alg: \"A256KW\" }\n```\n\n#### `importKey(keyMaterial, alg?)`\n\nImports a key from various formats. This is a flexible wrapper.\n\n- `keyMaterial`: The key to import. Can be:\n  - `CryptoKey`: Returned directly.\n  - `Uint8Array`: Returned directly (treated as raw symmetric key bytes).\n  - `string`: Encoded to `Uint8Array` and returned.\n  - `JWK_oct` (symmetric JWK with `k` property): The `k` value is Base64URL decoded and returned as `Uint8Array`.\n  - Other `JWK` types (asymmetric): Imported into a `CryptoKey`.\n- `alg` (optional): The JWA algorithm string. **Required** when importing asymmetric JWKs (e.g., RSA, EC) to provide context for `crypto.subtle.importKey`.\n\nReturns a `Promise` resolving to `CryptoKey` or `Uint8Array`.\n\n**Examples:**\n\n```ts\nimport { importKey } from \"unjwt/jwk\";\nimport { textEncoder, base64UrlDecode } from \"unjwt/utils\";\n\n// Import raw symmetric key bytes\nconst rawBytes = textEncoder.encode(\"a-32-byte-long-secret-key-123\"); // 32 bytes for AES-256 or HS256\nconst symmetricKeyBytes = await importKey(rawBytes);\nconsole.log(symmetricKeyBytes); // Uint8Array\n\n// Import a symmetric JWK (kty: \"oct\")\nconst octJwk = {\n  kty: \"oct\",\n  k: \"AyM1SysPpbyDfgZld3umj1qzKObwVMkoqQ-EstJQLr0\", // Example key\n};\nconst importedOctBytes = await importKey(octJwk); // Returns Uint8Array\nconsole.log(importedOctBytes); // Uint8Array (decoded from k)\n\n// Import an RSA Public Key JWK\nconst rsaPublicJwk = {\n  kty: \"RSA\",\n  n: \"0vx7agoebGcQSuuPiLJXZptN9nndrQmbXEps2aiAFbWhM78LhWx4cbbfAAtVT86zwu1RK7aPFFxuhDR1L6tSoc_BJECPebWKRXjBZCiFV4n3ok92YEnjsADC4Ue87zwRzH2J-TCwlcQrY3E9gGZJZL2g_2_5QjLhL0gR0xYj04_N4M\",\n  e: \"AQAB\",\n  alg: \"RS256\",\n  kid: \"rsa-pub-1\",\n};\nconst rsaPublicKey = await importKey(rsaPublicJwk, \"RS256\"); // 'alg' is crucial here\nconsole.log(rsaPublicKey); // CryptoKey\n```\n\n#### `exportKey(key, jwk?)`\n\nExports a `CryptoKey` to JWK format.\n\n- `key`: The `CryptoKey` to export (must be `extractable`).\n- `jwk` (optional): A partial `JWK` object to merge with the exported properties (e.g., to add `kid`, `use`, or override `alg`).\n\nReturns a `Promise\u003cJWK\u003e`.\n\n**Example:**\n\n```ts\nimport { generateKey, exportKey } from \"unjwt/jwk\";\n\nconst { publicKey } = await generateKey(\"ES256\"); // Generates an extractable CryptoKey\n\nconst jwk = await exportKey(publicKey, { kid: \"ec-key-001\", use: \"sig\" });\nconsole.log(jwk);\n// {\n//   kty: 'EC',\n//   crv: 'P-256',\n//   x: '...',\n//   y: '...',\n//   ext: true,\n//   key_ops: [ 'verify' ], // or as per generation\n//   kid: 'ec-key-001',\n//   use: 'sig'\n// }\n```\n\n#### `wrapKey(alg, keyToWrap, wrappingKey, options?)`\n\nWraps a Content Encryption Key (CEK).\n\n- `alg`: The JWA key management algorithm (e.g., `\"A128KW\"`, `\"RSA-OAEP\"`).\n- `keyToWrap`: The CEK to wrap (`CryptoKey` or `Uint8Array`).\n- `wrappingKey`: The Key Encryption Key (KEK) (`CryptoKey`, `JWK`, or password `string`/`Uint8Array` for PBES2).\n- `options` (optional): Algorithm-specific options (e.g., `p2s`, `p2c` for PBES2; `iv` for AES-GCMKW).\n\nReturns a `Promise\u003cWrapKeyResult\u003e` containing `encryptedKey` and other parameters like `iv`, `tag`, `epk`, `p2s`, `p2c` as needed by the algorithm.\n\n**Example (AES Key Wrap):**\n\n```ts\nimport { wrapKey, generateKey } from \"unjwt/jwk\";\nimport { randomBytes } from \"unjwt/utils\";\n\nconst cekToWrap = randomBytes(32); // e.g., a 256-bit AES key as Uint8Array\nconst kek = await generateKey(\"A128KW\"); // 128-bit AES Key Wrap key\n\nconst { encryptedKey } = await wrapKey(\"A128KW\", cekToWrap, kek);\nconsole.log(\"Wrapped CEK:\", encryptedKey); // Uint8Array\n```\n\n#### `unwrapKey(alg, wrappedKey, unwrappingKey, options?)`\n\nUnwraps a Content Encryption Key (CEK).\n\n- `alg`: The JWA key management algorithm.\n- `wrappedKey`: The encrypted CEK (`Uint8Array`).\n- `unwrappingKey`: The Key Decryption Key (KDK).\n- `options` (optional):\n  - `returnAs`: If `false`, returns `Uint8Array`. If `true` (default) or undefined, returns `CryptoKey`.\n  - `unwrappedKeyAlgorithm`: `AlgorithmIdentifier` for the imported CEK if `returnAs` is `true`.\n  - `keyUsage`: `KeyUsage[]` for the imported CEK if `returnAs` is `true`.\n  - `extractable`: Boolean for the imported CEK.\n  - Other algorithm-specific options (e.g., `p2s`, `p2c`, `iv`, `tag`, `epk`).\n\nReturns a `Promise` resolving to the unwrapped CEK as `CryptoKey` or `Uint8Array`.\n\n**Example (AES Key Unwrap):**\n\n```ts\nimport { unwrapKey, generateKey } from \"unjwt/jwk\";\n// const encryptedKey = ...; // From wrapKey example\n// const kdk = ...; // Same KEK used for wrapping\n\nasync function unwrapMyKey(encryptedKey: Uint8Array, kdk: CryptoKey) {\n  const unwrappedCekBytes = await unwrapKey(\"A128KW\", encryptedKey, kdk, {\n    returnAs: false, // Get raw bytes\n  });\n  console.log(\"Unwrapped CEK (bytes):\", unwrappedCekBytes); // Uint8Array\n\n  const unwrappedCekCryptoKey = await unwrapKey(\"A128KW\", encryptedKey, kdk, {\n    returnAs: true, // Get CryptoKey\n    unwrappedKeyAlgorithm: { name: \"AES-GCM\", length: 256 }, // Specify CEK's intended alg\n    keyUsage: [\"encrypt\", \"decrypt\"],\n  });\n  console.log(\"Unwrapped CEK (CryptoKey):\", unwrappedCekCryptoKey); // CryptoKey\n}\n```\n\n### Utility Functions\n\n`unjwt/utils` exports several helpful functions:\n\n- `base64UrlEncode(data: Uint8Array | string): string`\n- `base64UrlDecode(str?: string, toString?: boolean): Uint8Array | string` (Decodes to string by default, or `Uint8Array` if `toString` is `false`)\n- `randomBytes(length: number): Uint8Array`\n- `textEncoder: TextEncoder`\n- `textDecoder: TextDecoder`\n- Type guards: `isJWK(key)`, `isCryptoKey(key)`, `isCryptoKeyPair(keyPair)`\n\n## Development\n\n\u003cdetails\u003e\n\n\u003csummary\u003elocal development\u003c/summary\u003e\n\n- Clone this repository\n- Install latest LTS version of [Node.js](https://nodejs.org/en/)\n- Enable [Corepack](https://github.com/nodejs/corepack) using `corepack enable`\n- Install dependencies using `pnpm install`\n- Run interactive tests using `pnpm dev`\n\n\u003c/details\u003e\n\n## Credits\n\nOriginally developed by [Johann Schopplich](https://github.com/johannschopplich/unjwt).\nHeavily inspired by [Filip Skokan's work](https://github.com/panva/jose).\n\n## License\n\n\u003c!-- automd:contributors license=MIT --\u003e\n\nPublished under the [MIT](https://github.com/sandros94/unjwt/blob/main/LICENSE) license.\nMade by [community](https://github.com/sandros94/unjwt/graphs/contributors) 💛\n\u003cbr\u003e\u003cbr\u003e\n\u003ca href=\"https://github.com/sandros94/unjwt/graphs/contributors\"\u003e\n\u003cimg src=\"https://contrib.rocks/image?repo=sandros94/unjwt\" /\u003e\n\u003c/a\u003e\n\n\u003c!-- /automd --\u003e\n\n\u003c!-- automd:with-automd --\u003e\n\n---\n\n_🤖 auto updated with [automd](https://automd.unjs.io)_\n\n\u003c!-- /automd --\u003e\n","funding_links":["https://github.com/sponsors/sandros94"],"categories":[],"sub_categories":[],"project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fsandros94%2Funjwt","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fsandros94%2Funjwt","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fsandros94%2Funjwt/lists"}