1
0

Compare commits

...

9 Commits

Author SHA1 Message Date
e49bada1a5 2.5.2 2024-03-01 20:32:48 +01:00
c75c26044f remove math abs 2024-03-01 20:31:24 +01:00
5942b3d1bd clean up tests 2024-02-24 16:46:17 +01:00
c1214f897a 2.5.1 2024-02-23 23:46:56 +01:00
f3dfdff3bb fix falsly invalid tokens 2024-02-23 23:42:38 +01:00
0cd10e17f7 remove console.log 2024-02-22 23:24:19 +01:00
884371fac6 remove node from dev deps 2024-02-22 23:21:31 +01:00
83678c92eb 2.5.0 2024-02-22 23:04:39 +01:00
37fdf4f602 update readme 2024-02-22 23:03:05 +01:00
8 changed files with 284 additions and 442 deletions

View File

@@ -84,11 +84,13 @@ Signs a payload and returns the token.
#### Arguments #### Arguments
Argument | Type | Status | Default | Description Argument | Type | Status | Default | Description
----------- | -------- | -------- | ------- | ----------- ------------------------ | ------------------ | -------- | ----------- | -----------
`payload` | `object` | required | - | The payload object. To use `nbf` (Not Before) and/or `exp` (Expiration Time) add `nbf` and/or `exp` to the payload. `payload` | `object` | required | - | The payload object. To use `nbf` (Not Before) and/or `exp` (Expiration Time) add `nbf` and/or `exp` to the payload.
`secret` | `string` | required | - | A string which is used to sign the payload. `secret` | `string` | required | - | A string which is used to sign the payload.
`options` | `object` | optional | `{ algorithm: 'HS256' }` | The options object supporting `algorithm` and `keyid`. (See [Available Algorithms](#available-algorithms)) `options` | `string`, `object` | optional | `HS256` | Either the `algorithm` string or an object.
`options.algorithm` | `string` | optional | `HS256` | See [Available Algorithms](#available-algorithms)
`options.keyid` | `string` | optional | `undefined` | The `keyid` or `kid` to be set in the header of the resulting JWT.
#### `return` #### `return`
Returns token as a `string`. Returns token as a `string`.
@@ -100,11 +102,15 @@ Returns token as a `string`.
Verifies the integrity of the token and returns a boolean value. Verifies the integrity of the token and returns a boolean value.
Argument | Type | Status | Default | Description Argument | Type | Status | Default | Description
----------- | -------- | -------- | ------- | ----------- ------------------------ | ------------------ | -------- | ------- | -----------
`token` | `string` | required | - | The token string generated by `jwt.sign()`. `token` | `string` | required | - | The token string generated by `jwt.sign()`.
`secret` | `string` | required | - | The string which was used to sign the payload. `secret` | `string` | required | - | The string which was used to sign the payload.
`options` | `object` | optional | `{ algorithm: 'HS256', skipValidation: false, throwError: false }` | The options object supporting `algorithm`, `skipValidation` and `throwError`. (See [Available Algorithms](#available-algorithms)) `options` | `string`, `object` | optional | `HS256` | Either the `algorithm` string or an object.
`options.algorithm` | `string` | optional | `HS256` | See [Available Algorithms](#available-algorithms)
`options.clockTolerance` | `number` | optional | `0` | Clock tolerance in seconds, to help with slighly out of sync systems.
`options.throwError` | `boolean` | optional | `false` | By default this we will only throw implementation errors, only set this to `true` if you want verification errors to be thrown as well.
#### `throws` #### `throws`
If `options.throwError` is `true` and the token is invalid, an error will be thrown. If `options.throwError` is `true` and the token is invalid, an error will be thrown.

179
package-lock.json generated
View File

@@ -1,40 +1,26 @@
{ {
"name": "@tsndr/cloudflare-worker-jwt", "name": "@tsndr/cloudflare-worker-jwt",
"version": "2.4.7", "version": "2.5.2",
"lockfileVersion": 3, "lockfileVersion": 3,
"requires": true, "requires": true,
"packages": { "packages": {
"": { "": {
"name": "@tsndr/cloudflare-worker-jwt", "name": "@tsndr/cloudflare-worker-jwt",
"version": "2.4.7", "version": "2.5.2",
"license": "MIT", "license": "MIT",
"devDependencies": { "devDependencies": {
"@cloudflare/workers-types": "^4.20240208.0", "@cloudflare/workers-types": "^4.20240208.0",
"@edge-runtime/vm": "^3.2.0", "@edge-runtime/vm": "^3.2.0",
"@types/node": "^20.11.19",
"ts-node": "^10.9.2",
"typescript": "^5.3.3", "typescript": "^5.3.3",
"vitest": "^1.3.1" "vitest": "^1.3.1"
} }
}, },
"node_modules/@cloudflare/workers-types": { "node_modules/@cloudflare/workers-types": {
"version": "4.20240208.0", "version": "4.20240222.0",
"resolved": "https://registry.npmjs.org/@cloudflare/workers-types/-/workers-types-4.20240208.0.tgz", "resolved": "https://registry.npmjs.org/@cloudflare/workers-types/-/workers-types-4.20240222.0.tgz",
"integrity": "sha512-MVGTTjZpJu4kJONvai5SdJzWIhOJbuweVZ3goI7FNyG+JdoQH41OoB+nMhLsX626vPLZVWGPIWsiSo/WZHzgQw==", "integrity": "sha512-luO0BdK3rLlCv3B240+cTrfqm+XSbHtpk+88aJtGwzyVK9QF/Xz8lBgE/oZZLN8nCTmOvxAZnszyxUuZ8GP8Cg==",
"dev": true "dev": true
}, },
"node_modules/@cspotcode/source-map-support": {
"version": "0.8.1",
"resolved": "https://registry.npmjs.org/@cspotcode/source-map-support/-/source-map-support-0.8.1.tgz",
"integrity": "sha512-IchNf6dN4tHoMFIn/7OE8LWZ19Y6q/67Bmf6vnGREv8RSbBVb9LPJxEcnwrcwX6ixSvaiGoomAUvu4YSxXrVgw==",
"dev": true,
"dependencies": {
"@jridgewell/trace-mapping": "0.3.9"
},
"engines": {
"node": ">=12"
}
},
"node_modules/@edge-runtime/primitives": { "node_modules/@edge-runtime/primitives": {
"version": "4.1.0", "version": "4.1.0",
"resolved": "https://registry.npmjs.org/@edge-runtime/primitives/-/primitives-4.1.0.tgz", "resolved": "https://registry.npmjs.org/@edge-runtime/primitives/-/primitives-4.1.0.tgz",
@@ -436,31 +422,12 @@
"node": "^14.15.0 || ^16.10.0 || >=18.0.0" "node": "^14.15.0 || ^16.10.0 || >=18.0.0"
} }
}, },
"node_modules/@jridgewell/resolve-uri": {
"version": "3.1.2",
"resolved": "https://registry.npmjs.org/@jridgewell/resolve-uri/-/resolve-uri-3.1.2.tgz",
"integrity": "sha512-bRISgCIjP20/tbWSPWMEi54QVPRZExkuD9lJL+UIxUKtwVJA8wW1Trb1jMs1RFXo1CBTNZ/5hpC9QvmKWdopKw==",
"dev": true,
"engines": {
"node": ">=6.0.0"
}
},
"node_modules/@jridgewell/sourcemap-codec": { "node_modules/@jridgewell/sourcemap-codec": {
"version": "1.4.15", "version": "1.4.15",
"resolved": "https://registry.npmjs.org/@jridgewell/sourcemap-codec/-/sourcemap-codec-1.4.15.tgz", "resolved": "https://registry.npmjs.org/@jridgewell/sourcemap-codec/-/sourcemap-codec-1.4.15.tgz",
"integrity": "sha512-eF2rxCRulEKXHTRiDrDy6erMYWqNw4LPdQ8UQA4huuxaQsVeRPFl2oM8oDGxMFhJUWZf9McpLtJasDDZb/Bpeg==", "integrity": "sha512-eF2rxCRulEKXHTRiDrDy6erMYWqNw4LPdQ8UQA4huuxaQsVeRPFl2oM8oDGxMFhJUWZf9McpLtJasDDZb/Bpeg==",
"dev": true "dev": true
}, },
"node_modules/@jridgewell/trace-mapping": {
"version": "0.3.9",
"resolved": "https://registry.npmjs.org/@jridgewell/trace-mapping/-/trace-mapping-0.3.9.tgz",
"integrity": "sha512-3Belt6tdc8bPgAtbcmdtNJlirVoTmEb5e2gC94PnkwEW9jI6CAHUeoG85tjWP5WquqfavoMtMwiG4P926ZKKuQ==",
"dev": true,
"dependencies": {
"@jridgewell/resolve-uri": "^3.0.3",
"@jridgewell/sourcemap-codec": "^1.4.10"
}
},
"node_modules/@rollup/rollup-android-arm-eabi": { "node_modules/@rollup/rollup-android-arm-eabi": {
"version": "4.12.0", "version": "4.12.0",
"resolved": "https://registry.npmjs.org/@rollup/rollup-android-arm-eabi/-/rollup-android-arm-eabi-4.12.0.tgz", "resolved": "https://registry.npmjs.org/@rollup/rollup-android-arm-eabi/-/rollup-android-arm-eabi-4.12.0.tgz",
@@ -636,45 +603,12 @@
"integrity": "sha512-+Fj43pSMwJs4KRrH/938Uf+uAELIgVBmQzg/q1YG10djyfA3TnrU8N8XzqCh/okZdszqBQTZf96idMfE5lnwTA==", "integrity": "sha512-+Fj43pSMwJs4KRrH/938Uf+uAELIgVBmQzg/q1YG10djyfA3TnrU8N8XzqCh/okZdszqBQTZf96idMfE5lnwTA==",
"dev": true "dev": true
}, },
"node_modules/@tsconfig/node10": {
"version": "1.0.9",
"resolved": "https://registry.npmjs.org/@tsconfig/node10/-/node10-1.0.9.tgz",
"integrity": "sha512-jNsYVVxU8v5g43Erja32laIDHXeoNvFEpX33OK4d6hljo3jDhCBDhx5dhCCTMWUojscpAagGiRkBKxpdl9fxqA==",
"dev": true
},
"node_modules/@tsconfig/node12": {
"version": "1.0.11",
"resolved": "https://registry.npmjs.org/@tsconfig/node12/-/node12-1.0.11.tgz",
"integrity": "sha512-cqefuRsh12pWyGsIoBKJA9luFu3mRxCA+ORZvA4ktLSzIuCUtWVxGIuXigEwO5/ywWFMZ2QEGKWvkZG1zDMTag==",
"dev": true
},
"node_modules/@tsconfig/node14": {
"version": "1.0.3",
"resolved": "https://registry.npmjs.org/@tsconfig/node14/-/node14-1.0.3.tgz",
"integrity": "sha512-ysT8mhdixWK6Hw3i1V2AeRqZ5WfXg1G43mqoYlM2nc6388Fq5jcXyr5mRsqViLx/GJYdoL0bfXD8nmF+Zn/Iow==",
"dev": true
},
"node_modules/@tsconfig/node16": {
"version": "1.0.4",
"resolved": "https://registry.npmjs.org/@tsconfig/node16/-/node16-1.0.4.tgz",
"integrity": "sha512-vxhUy4J8lyeyinH7Azl1pdd43GJhZH/tP2weN8TntQblOY+A0XbT8DJk1/oCPuOOyg/Ja757rG0CgHcWC8OfMA==",
"dev": true
},
"node_modules/@types/estree": { "node_modules/@types/estree": {
"version": "1.0.5", "version": "1.0.5",
"resolved": "https://registry.npmjs.org/@types/estree/-/estree-1.0.5.tgz", "resolved": "https://registry.npmjs.org/@types/estree/-/estree-1.0.5.tgz",
"integrity": "sha512-/kYRxGDLWzHOB7q+wtSUQlFrtcdUccpfy+X+9iMBpHK8QLLhx2wIPYuS5DYtR9Wa/YlZAbIovy7qVdB1Aq6Lyw==", "integrity": "sha512-/kYRxGDLWzHOB7q+wtSUQlFrtcdUccpfy+X+9iMBpHK8QLLhx2wIPYuS5DYtR9Wa/YlZAbIovy7qVdB1Aq6Lyw==",
"dev": true "dev": true
}, },
"node_modules/@types/node": {
"version": "20.11.19",
"resolved": "https://registry.npmjs.org/@types/node/-/node-20.11.19.tgz",
"integrity": "sha512-7xMnVEcZFu0DikYjWOlRq7NTPETrm7teqUT2WkQjrTIkEgUyyGdWsj/Zg8bEJt5TNklzbPD1X3fqfsHw3SpapQ==",
"dev": true,
"dependencies": {
"undici-types": "~5.26.4"
}
},
"node_modules/@vitest/expect": { "node_modules/@vitest/expect": {
"version": "1.3.1", "version": "1.3.1",
"resolved": "https://registry.npmjs.org/@vitest/expect/-/expect-1.3.1.tgz", "resolved": "https://registry.npmjs.org/@vitest/expect/-/expect-1.3.1.tgz",
@@ -777,12 +711,6 @@
"url": "https://github.com/chalk/ansi-styles?sponsor=1" "url": "https://github.com/chalk/ansi-styles?sponsor=1"
} }
}, },
"node_modules/arg": {
"version": "4.1.3",
"resolved": "https://registry.npmjs.org/arg/-/arg-4.1.3.tgz",
"integrity": "sha512-58S9QDqG0Xx27YwPSt9fJxivjYl432YCwfDMfZ+71RAqUrZef7LrKQZ3LHLOwCS4FLNBplP533Zx895SeOCHvA==",
"dev": true
},
"node_modules/assertion-error": { "node_modules/assertion-error": {
"version": "1.1.0", "version": "1.1.0",
"resolved": "https://registry.npmjs.org/assertion-error/-/assertion-error-1.1.0.tgz", "resolved": "https://registry.npmjs.org/assertion-error/-/assertion-error-1.1.0.tgz",
@@ -831,12 +759,6 @@
"node": "*" "node": "*"
} }
}, },
"node_modules/create-require": {
"version": "1.1.1",
"resolved": "https://registry.npmjs.org/create-require/-/create-require-1.1.1.tgz",
"integrity": "sha512-dcKFX3jn0MpIaXjisoRvexIJVEKzaq7z2rZKxf+MSr9TkdmHmsU4m2lcLojrj/FHl8mk5VxMmYA+ftRkP/3oKQ==",
"dev": true
},
"node_modules/cross-spawn": { "node_modules/cross-spawn": {
"version": "7.0.3", "version": "7.0.3",
"resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-7.0.3.tgz", "resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-7.0.3.tgz",
@@ -880,15 +802,6 @@
"node": ">=6" "node": ">=6"
} }
}, },
"node_modules/diff": {
"version": "4.0.2",
"resolved": "https://registry.npmjs.org/diff/-/diff-4.0.2.tgz",
"integrity": "sha512-58lmxKSA4BNyLz+HHMUzlOEpg09FV+ev6ZMe3vJihgdxzgcwZ8VoEEPmALCZG9LmqfVoNMMKpttIYTVG6uDY7A==",
"dev": true,
"engines": {
"node": ">=0.3.1"
}
},
"node_modules/diff-sequences": { "node_modules/diff-sequences": {
"version": "29.6.3", "version": "29.6.3",
"resolved": "https://registry.npmjs.org/diff-sequences/-/diff-sequences-29.6.3.tgz", "resolved": "https://registry.npmjs.org/diff-sequences/-/diff-sequences-29.6.3.tgz",
@@ -1079,12 +992,6 @@
"node": ">=12" "node": ">=12"
} }
}, },
"node_modules/make-error": {
"version": "1.3.6",
"resolved": "https://registry.npmjs.org/make-error/-/make-error-1.3.6.tgz",
"integrity": "sha512-s8UhlNe7vPKomQhC1qFelMokr/Sc3AgNbso3n74mVPA5LTZwkB9NlXf4XPamLxJE8h0gh73rM94xvwRT2CVInw==",
"dev": true
},
"node_modules/merge-stream": { "node_modules/merge-stream": {
"version": "2.0.0", "version": "2.0.0",
"resolved": "https://registry.npmjs.org/merge-stream/-/merge-stream-2.0.0.tgz", "resolved": "https://registry.npmjs.org/merge-stream/-/merge-stream-2.0.0.tgz",
@@ -1104,9 +1011,9 @@
} }
}, },
"node_modules/mlly": { "node_modules/mlly": {
"version": "1.6.0", "version": "1.6.1",
"resolved": "https://registry.npmjs.org/mlly/-/mlly-1.6.0.tgz", "resolved": "https://registry.npmjs.org/mlly/-/mlly-1.6.1.tgz",
"integrity": "sha512-YOvg9hfYQmnaB56Yb+KrJE2u0Yzz5zR+sLejEvF4fzwzV1Al6hkf2vyHTwqCRyv0hCi9rVCqVoXpyYevQIRwLQ==", "integrity": "sha512-vLgaHvaeunuOXHSmEbZ9izxPx3USsk8KCQ8iC+aTlp5sKRSoZvwhHh5L9VbKSaVC6sJDqbyohIS76E2VmHIPAA==",
"dev": true, "dev": true,
"dependencies": { "dependencies": {
"acorn": "^8.11.3", "acorn": "^8.11.3",
@@ -1140,9 +1047,9 @@
} }
}, },
"node_modules/npm-run-path": { "node_modules/npm-run-path": {
"version": "5.2.0", "version": "5.3.0",
"resolved": "https://registry.npmjs.org/npm-run-path/-/npm-run-path-5.2.0.tgz", "resolved": "https://registry.npmjs.org/npm-run-path/-/npm-run-path-5.3.0.tgz",
"integrity": "sha512-W4/tgAXFqFA0iL7fk0+uQ3g7wkL8xJmx3XdK0VGb4cHW//eZTtKGvFBBoRKVTpY7n6ze4NL9ly7rgXcHufqXKg==", "integrity": "sha512-ppwTtiJZq0O/ai0z7yfudtBpWIoxM8yE6nHi1X47eFR2EWORqfbu6CnPlNsjeN683eT0qG6H/Pyf9fCcvjnnnQ==",
"dev": true, "dev": true,
"dependencies": { "dependencies": {
"path-key": "^4.0.0" "path-key": "^4.0.0"
@@ -1425,49 +1332,6 @@
"node": ">=14.0.0" "node": ">=14.0.0"
} }
}, },
"node_modules/ts-node": {
"version": "10.9.2",
"resolved": "https://registry.npmjs.org/ts-node/-/ts-node-10.9.2.tgz",
"integrity": "sha512-f0FFpIdcHgn8zcPSbf1dRevwt047YMnaiJM3u2w2RewrB+fob/zePZcrOyQoLMMO7aBIddLcQIEK5dYjkLnGrQ==",
"dev": true,
"dependencies": {
"@cspotcode/source-map-support": "^0.8.0",
"@tsconfig/node10": "^1.0.7",
"@tsconfig/node12": "^1.0.7",
"@tsconfig/node14": "^1.0.0",
"@tsconfig/node16": "^1.0.2",
"acorn": "^8.4.1",
"acorn-walk": "^8.1.1",
"arg": "^4.1.0",
"create-require": "^1.1.0",
"diff": "^4.0.1",
"make-error": "^1.1.1",
"v8-compile-cache-lib": "^3.0.1",
"yn": "3.1.1"
},
"bin": {
"ts-node": "dist/bin.js",
"ts-node-cwd": "dist/bin-cwd.js",
"ts-node-esm": "dist/bin-esm.js",
"ts-node-script": "dist/bin-script.js",
"ts-node-transpile-only": "dist/bin-transpile.js",
"ts-script": "dist/bin-script-deprecated.js"
},
"peerDependencies": {
"@swc/core": ">=1.2.50",
"@swc/wasm": ">=1.2.50",
"@types/node": "*",
"typescript": ">=2.7"
},
"peerDependenciesMeta": {
"@swc/core": {
"optional": true
},
"@swc/wasm": {
"optional": true
}
}
},
"node_modules/type-detect": { "node_modules/type-detect": {
"version": "4.0.8", "version": "4.0.8",
"resolved": "https://registry.npmjs.org/type-detect/-/type-detect-4.0.8.tgz", "resolved": "https://registry.npmjs.org/type-detect/-/type-detect-4.0.8.tgz",
@@ -1496,18 +1360,6 @@
"integrity": "sha512-Hhy+BhRBleFjpJ2vchUNN40qgkh0366FWJGqVLYBHev0vpHTrXSA0ryT+74UiW6KWsldNurQMKGqCm1M2zBciQ==", "integrity": "sha512-Hhy+BhRBleFjpJ2vchUNN40qgkh0366FWJGqVLYBHev0vpHTrXSA0ryT+74UiW6KWsldNurQMKGqCm1M2zBciQ==",
"dev": true "dev": true
}, },
"node_modules/undici-types": {
"version": "5.26.5",
"resolved": "https://registry.npmjs.org/undici-types/-/undici-types-5.26.5.tgz",
"integrity": "sha512-JlCMO+ehdEIKqlFxk6IfVoAUVmgz7cU7zD/h9XZ0qzeosSHmUJVOzSQvvYSYWXkFXC+IfLKSIffhv0sVZup6pA==",
"dev": true
},
"node_modules/v8-compile-cache-lib": {
"version": "3.0.1",
"resolved": "https://registry.npmjs.org/v8-compile-cache-lib/-/v8-compile-cache-lib-3.0.1.tgz",
"integrity": "sha512-wa7YjyUGfNZngI/vtK0UHAN+lgDCxBPCylVXGp0zu59Fz5aiGtNXaq3DhIov063MorB+VfufLh3JlF2KdTK3xg==",
"dev": true
},
"node_modules/vite": { "node_modules/vite": {
"version": "5.1.4", "version": "5.1.4",
"resolved": "https://registry.npmjs.org/vite/-/vite-5.1.4.tgz", "resolved": "https://registry.npmjs.org/vite/-/vite-5.1.4.tgz",
@@ -1681,15 +1533,6 @@
"node": ">=8" "node": ">=8"
} }
}, },
"node_modules/yn": {
"version": "3.1.1",
"resolved": "https://registry.npmjs.org/yn/-/yn-3.1.1.tgz",
"integrity": "sha512-Ux4ygGWsu2c7isFWe8Yu1YluJmqVhxqK2cLXNQA5AcC3QfbGNpM7fu0Y8b/z16pXLnFxZYvWhd3fhBY9DLmC6Q==",
"dev": true,
"engines": {
"node": ">=6"
}
},
"node_modules/yocto-queue": { "node_modules/yocto-queue": {
"version": "1.0.0", "version": "1.0.0",
"resolved": "https://registry.npmjs.org/yocto-queue/-/yocto-queue-1.0.0.tgz", "resolved": "https://registry.npmjs.org/yocto-queue/-/yocto-queue-1.0.0.tgz",

View File

@@ -1,6 +1,6 @@
{ {
"name": "@tsndr/cloudflare-worker-jwt", "name": "@tsndr/cloudflare-worker-jwt",
"version": "2.4.7", "version": "2.5.2",
"description": "A lightweight JWT implementation with ZERO dependencies for Cloudflare Worker", "description": "A lightweight JWT implementation with ZERO dependencies for Cloudflare Worker",
"type": "module", "type": "module",
"exports": "./index.js", "exports": "./index.js",
@@ -32,8 +32,6 @@
"devDependencies": { "devDependencies": {
"@cloudflare/workers-types": "^4.20240208.0", "@cloudflare/workers-types": "^4.20240208.0",
"@edge-runtime/vm": "^3.2.0", "@edge-runtime/vm": "^3.2.0",
"@types/node": "^20.11.19",
"ts-node": "^10.9.2",
"typescript": "^5.3.3", "typescript": "^5.3.3",
"vitest": "^1.3.1" "vitest": "^1.3.1"
} }

View File

@@ -7,14 +7,14 @@ import {
decodePayload decodePayload
} from "./utils" } from "./utils"
if (typeof crypto === 'undefined' || !crypto.subtle) if (typeof crypto === "undefined" || !crypto.subtle)
throw new Error('SubtleCrypto not supported!') throw new Error("SubtleCrypto not supported!")
/** /**
* @typedef JwtAlgorithm * @typedef JwtAlgorithm
* @type {'ES256' | 'ES384' | 'ES512' | 'HS256' | 'HS384' | 'HS512' | 'RS256' | 'RS384' | 'RS512'} * @type {"ES256" | "ES384" | "ES512" | "HS256" | "HS384" | "HS512" | "RS256" | "RS384" | "RS512"}
*/ */
export type JwtAlgorithm = 'ES256' | 'ES384' | 'ES512' | 'HS256' | 'HS384' | 'HS512' | 'RS256' | 'RS384' | 'RS512' export type JwtAlgorithm = "ES256" | "ES384" | "ES512" | "HS256" | "HS384" | "HS512" | "RS256" | "RS384" | "RS512"
/** /**
* @typedef JwtAlgorithms * @typedef JwtAlgorithms
@@ -123,15 +123,15 @@ export type JwtData<Payload = {}, Header = {}> = {
} }
const algorithms: JwtAlgorithms = { const algorithms: JwtAlgorithms = {
ES256: { name: 'ECDSA', namedCurve: 'P-256', hash: { name: 'SHA-256' } }, ES256: { name: "ECDSA", namedCurve: "P-256", hash: { name: "SHA-256" } },
ES384: { name: 'ECDSA', namedCurve: 'P-384', hash: { name: 'SHA-384' } }, ES384: { name: "ECDSA", namedCurve: "P-384", hash: { name: "SHA-384" } },
ES512: { name: 'ECDSA', namedCurve: 'P-521', hash: { name: 'SHA-512' } }, ES512: { name: "ECDSA", namedCurve: "P-521", hash: { name: "SHA-512" } },
HS256: { name: 'HMAC', hash: { name: 'SHA-256' } }, HS256: { name: "HMAC", hash: { name: "SHA-256" } },
HS384: { name: 'HMAC', hash: { name: 'SHA-384' } }, HS384: { name: "HMAC", hash: { name: "SHA-384" } },
HS512: { name: 'HMAC', hash: { name: 'SHA-512' } }, HS512: { name: "HMAC", hash: { name: "SHA-512" } },
RS256: { name: 'RSASSA-PKCS1-v1_5', hash: { name: 'SHA-256' } }, RS256: { name: "RSASSA-PKCS1-v1_5", hash: { name: "SHA-256" } },
RS384: { name: 'RSASSA-PKCS1-v1_5', hash: { name: 'SHA-384' } }, RS384: { name: "RSASSA-PKCS1-v1_5", hash: { name: "SHA-384" } },
RS512: { name: 'RSASSA-PKCS1-v1_5', hash: { name: 'SHA-512' } } RS512: { name: "RSASSA-PKCS1-v1_5", hash: { name: "SHA-512" } }
} }
/** /**
@@ -139,36 +139,36 @@ const algorithms: JwtAlgorithms = {
* *
* @param {JwtPayload} payload The payload object. To use `nbf` (Not Before) and/or `exp` (Expiration Time) add `nbf` and/or `exp` to the payload. * @param {JwtPayload} payload The payload object. To use `nbf` (Not Before) and/or `exp` (Expiration Time) add `nbf` and/or `exp` to the payload.
* @param {string | JsonWebKey | CryptoKey} secret A string which is used to sign the payload. * @param {string | JsonWebKey | CryptoKey} secret A string which is used to sign the payload.
* @param {JwtSignOptions | JwtAlgorithm | string} [options={ algorithm: 'HS256', header: { typ: 'JWT' } }] The options object or the algorithm. * @param {JwtSignOptions | JwtAlgorithm | string} [options={ algorithm: "HS256", header: { typ: "JWT" } }] The options object or the algorithm.
* @throws {Error} If there's a validation issue. * @throws {Error} If there"s a validation issue.
* @returns {Promise<string>} Returns token as a `string`. * @returns {Promise<string>} Returns token as a `string`.
*/ */
export async function sign<Payload = {}, Header = {}>(payload: JwtPayload<Payload>, secret: string | JsonWebKey, options: JwtSignOptions<Header> | JwtAlgorithm = 'HS256'): Promise<string> { export async function sign<Payload = {}, Header = {}>(payload: JwtPayload<Payload>, secret: string | JsonWebKey, options: JwtSignOptions<Header> | JwtAlgorithm = "HS256"): Promise<string> {
if (typeof options === 'string') if (typeof options === "string")
options = { algorithm: options } options = { algorithm: options }
options = { algorithm: 'HS256', header: { typ: 'JWT' } as JwtHeader<Header>, ...options } options = { algorithm: "HS256", header: { typ: "JWT" } as JwtHeader<Header>, ...options }
if (!payload || typeof payload !== 'object') if (!payload || typeof payload !== "object")
throw new Error('payload must be an object') throw new Error("payload must be an object")
if (!secret || (typeof secret !== 'string' && typeof secret !== 'object')) if (!secret || (typeof secret !== "string" && typeof secret !== "object"))
throw new Error('secret must be a string, a JWK object or a CryptoKey object') throw new Error("secret must be a string, a JWK object or a CryptoKey object")
if (typeof options.algorithm !== 'string') if (typeof options.algorithm !== "string")
throw new Error('options.algorithm must be a string') throw new Error("options.algorithm must be a string")
const algorithm: SubtleCryptoImportKeyAlgorithm = algorithms[options.algorithm] const algorithm: SubtleCryptoImportKeyAlgorithm = algorithms[options.algorithm]
if (!algorithm) if (!algorithm)
throw new Error('algorithm not found') throw new Error("algorithm not found")
if (!payload.iat) if (!payload.iat)
payload.iat = Math.floor(Date.now() / 1000) payload.iat = Math.floor(Date.now() / 1000)
const partialToken = `${textToBase64Url(JSON.stringify({ ...options.header, alg: options.algorithm }))}.${textToBase64Url(JSON.stringify(payload))}` const partialToken = `${textToBase64Url(JSON.stringify({ ...options.header, alg: options.algorithm }))}.${textToBase64Url(JSON.stringify(payload))}`
const key = secret instanceof CryptoKey ? secret : await importKey(secret, algorithm, ['sign']) const key = secret instanceof CryptoKey ? secret : await importKey(secret, algorithm, ["sign"])
const signature = await crypto.subtle.sign(algorithm, key, textToArrayBuffer(partialToken)) const signature = await crypto.subtle.sign(algorithm, key, textToArrayBuffer(partialToken))
return `${partialToken}.${arrayBufferToBase64Url(signature)}` return `${partialToken}.${arrayBufferToBase64Url(signature)}`
@@ -180,54 +180,54 @@ export async function sign<Payload = {}, Header = {}>(payload: JwtPayload<Payloa
* @param {string} token The token string generated by `jwt.sign()`. * @param {string} token The token string generated by `jwt.sign()`.
* @param {string | JsonWebKey | CryptoKey} secret The string which was used to sign the payload. * @param {string | JsonWebKey | CryptoKey} secret The string which was used to sign the payload.
* @param {JWTVerifyOptions | JWTAlgorithm} options The options object or the algorithm. * @param {JWTVerifyOptions | JWTAlgorithm} options The options object or the algorithm.
* @throws {Error | string} Throws an error `string` if the token is invalid or an `Error-Object` if there's a validation issue. * @throws {Error | string} Throws an error `string` if the token is invalid or an `Error-Object` if there"s a validation issue.
* @returns {Promise<boolean>} Returns `true` if signature, `nbf` (if set) and `exp` (if set) are valid, otherwise returns `false`. * @returns {Promise<boolean>} Returns `true` if signature, `nbf` (if set) and `exp` (if set) are valid, otherwise returns `false`.
*/ */
export async function verify(token: string, secret: string | JsonWebKey | CryptoKey, options: JwtVerifyOptions | JwtAlgorithm = 'HS256'): Promise<boolean> { export async function verify(token: string, secret: string | JsonWebKey | CryptoKey, options: JwtVerifyOptions | JwtAlgorithm = "HS256"): Promise<boolean> {
if (typeof options === 'string') if (typeof options === "string")
options = { algorithm: options } options = { algorithm: options }
options = { algorithm: 'HS256', clockTolerance: 0, throwError: false, ...options } options = { algorithm: "HS256", clockTolerance: 0, throwError: false, ...options }
if (typeof token !== 'string') if (typeof token !== "string")
throw new Error('token must be a string') throw new Error("token must be a string")
if (typeof secret !== 'string' && typeof secret !== 'object') if (typeof secret !== "string" && typeof secret !== "object")
throw new Error('secret must be a string, a JWK object or a CryptoKey object') throw new Error("secret must be a string, a JWK object or a CryptoKey object")
if (typeof options.algorithm !== 'string') if (typeof options.algorithm !== "string")
throw new Error('options.algorithm must be a string') throw new Error("options.algorithm must be a string")
const tokenParts = token.split('.') const tokenParts = token.split(".")
if (tokenParts.length !== 3) if (tokenParts.length !== 3)
throw new Error('token must consist of 3 parts') throw new Error("token must consist of 3 parts")
const algorithm: SubtleCryptoImportKeyAlgorithm = algorithms[options.algorithm] const algorithm: SubtleCryptoImportKeyAlgorithm = algorithms[options.algorithm]
if (!algorithm) if (!algorithm)
throw new Error('algorithm not found') throw new Error("algorithm not found")
const { header, payload } = decode(token) const { header, payload } = decode(token)
if (header?.alg !== options.algorithm) { if (header?.alg !== options.algorithm) {
if (options.throwError) if (options.throwError)
throw new Error('ALG_MISMATCH') throw new Error("ALG_MISMATCH")
return false return false
} }
try { try {
if (!payload) if (!payload)
throw new Error('PARSE_ERROR') throw new Error("PARSE_ERROR")
const now = Math.floor(Date.now() / 1000) const now = Math.floor(Date.now() / 1000)
if (payload.nbf && Math.abs(payload.nbf - now) > (options.clockTolerance ?? 0)) if (payload.nbf && payload.nbf > now && (payload.nbf - now) > (options.clockTolerance ?? 0))
throw new Error('NOT_YET_VALID') throw new Error("NOT_YET_VALID")
if (payload.exp && Math.abs(payload.exp - now) > (options.clockTolerance ?? 0)) if (payload.exp && payload.exp <= now && (now - payload.exp) > (options.clockTolerance ?? 0))
throw new Error('EXPIRED') throw new Error("EXPIRED")
const key = secret instanceof CryptoKey ? secret : await importKey(secret, algorithm, ['verify']) const key = secret instanceof CryptoKey ? secret : await importKey(secret, algorithm, ["verify"])
return await crypto.subtle.verify(algorithm, key, base64UrlToArrayBuffer(tokenParts[2]), textToArrayBuffer(`${tokenParts[0]}.${tokenParts[1]}`)) return await crypto.subtle.verify(algorithm, key, base64UrlToArrayBuffer(tokenParts[2]), textToArrayBuffer(`${tokenParts[0]}.${tokenParts[1]}`))
} catch(err) { } catch(err) {
@@ -245,8 +245,8 @@ export async function verify(token: string, secret: string | JsonWebKey | Crypto
*/ */
export function decode<Payload = {}, Header = {}>(token: string): JwtData<Payload, Header> { export function decode<Payload = {}, Header = {}>(token: string): JwtData<Payload, Header> {
return { return {
header: decodePayload<JwtHeader<Header>>(token.split('.')[0].replace(/-/g, '+').replace(/_/g, '/')), header: decodePayload<JwtHeader<Header>>(token.split(".")[0].replace(/-/g, "+").replace(/_/g, "/")),
payload: decodePayload<JwtPayload<Payload>>(token.split('.')[1].replace(/-/g, '+').replace(/_/g, '/')) payload: decodePayload<JwtPayload<Payload>>(token.split(".")[1].replace(/-/g, "+").replace(/_/g, "/"))
} }
} }

View File

@@ -1,5 +1,5 @@
export function bytesToByteString(bytes: Uint8Array): string { export function bytesToByteString(bytes: Uint8Array): string {
let byteStr = '' let byteStr = ""
for (let i = 0; i < bytes.byteLength; i++) { for (let i = 0; i < bytes.byteLength; i++) {
byteStr += String.fromCharCode(bytes[i]) byteStr += String.fromCharCode(bytes[i])
} }
@@ -31,25 +31,25 @@ export function arrayBufferToText(arrayBuffer: ArrayBuffer): string {
} }
export function arrayBufferToBase64Url(arrayBuffer: ArrayBuffer): string { export function arrayBufferToBase64Url(arrayBuffer: ArrayBuffer): string {
return arrayBufferToBase64String(arrayBuffer).replace(/=/g, '').replace(/\+/g, '-').replace(/\//g, '_') return arrayBufferToBase64String(arrayBuffer).replace(/=/g, "").replace(/\+/g, "-").replace(/\//g, "_")
} }
export function base64UrlToArrayBuffer(b64url: string): ArrayBuffer { export function base64UrlToArrayBuffer(b64url: string): ArrayBuffer {
return base64StringToArrayBuffer(b64url.replace(/-/g, '+').replace(/_/g, '/').replace(/\s/g, '')) return base64StringToArrayBuffer(b64url.replace(/-/g, "+").replace(/_/g, "/").replace(/\s/g, ""))
} }
export function textToBase64Url(str: string): string { export function textToBase64Url(str: string): string {
const encoder = new TextEncoder(); const encoder = new TextEncoder();
const charCodes = encoder.encode(str); const charCodes = encoder.encode(str);
const binaryStr = String.fromCharCode(...charCodes); const binaryStr = String.fromCharCode(...charCodes);
return btoa(binaryStr).replace(/=/g, '').replace(/\+/g, '-').replace(/\//g, '_') return btoa(binaryStr).replace(/=/g, "").replace(/\+/g, "-").replace(/\//g, "_")
} }
export function pemToBinary(pem: string): ArrayBuffer { export function pemToBinary(pem: string): ArrayBuffer {
return base64StringToArrayBuffer(pem.replace(/-+(BEGIN|END).*/g, '').replace(/\s/g, '')) return base64StringToArrayBuffer(pem.replace(/-+(BEGIN|END).*/g, "").replace(/\s/g, ""))
} }
type KeyUsages = 'sign' | 'verify'; type KeyUsages = "sign" | "verify";
export async function importTextSecret(key: string, algorithm: SubtleCryptoImportKeyAlgorithm, keyUsages: KeyUsages[]): Promise<CryptoKey> { export async function importTextSecret(key: string, algorithm: SubtleCryptoImportKeyAlgorithm, keyUsages: KeyUsages[]): Promise<CryptoKey> {
return await crypto.subtle.importKey("raw", textToArrayBuffer(key), algorithm, true, keyUsages) return await crypto.subtle.importKey("raw", textToArrayBuffer(key), algorithm, true, keyUsages)
} }
@@ -67,16 +67,16 @@ export async function importPrivateKey(key: string, algorithm: SubtleCryptoImpor
} }
export async function importKey(key: string | JsonWebKey, algorithm: SubtleCryptoImportKeyAlgorithm, keyUsages: KeyUsages[]): Promise<CryptoKey> { export async function importKey(key: string | JsonWebKey, algorithm: SubtleCryptoImportKeyAlgorithm, keyUsages: KeyUsages[]): Promise<CryptoKey> {
if (typeof key === 'object') if (typeof key === "object")
return importJwk(key, algorithm, keyUsages) return importJwk(key, algorithm, keyUsages)
if (typeof key !== 'string') if (typeof key !== "string")
throw new Error('Unsupported key type!') throw new Error("Unsupported key type!")
if (key.includes('PUBLIC')) if (key.includes("PUBLIC"))
return importPublicKey(key, algorithm, keyUsages) return importPublicKey(key, algorithm, keyUsages)
if (key.includes('PRIVATE')) if (key.includes("PRIVATE"))
return importPrivateKey(key, algorithm, keyUsages) return importPrivateKey(key, algorithm, keyUsages)
return importTextSecret(key, algorithm, keyUsages) return importTextSecret(key, algorithm, keyUsages)
@@ -85,7 +85,7 @@ export async function importKey(key: string | JsonWebKey, algorithm: SubtleCrypt
export function decodePayload<T = any>(raw: string): T | undefined { export function decodePayload<T = any>(raw: string): T | undefined {
try { try {
const bytes = Array.from(atob(raw), char => char.charCodeAt(0)); const bytes = Array.from(atob(raw), char => char.charCodeAt(0));
const decodedString = new TextDecoder('utf-8').decode(new Uint8Array(bytes)); const decodedString = new TextDecoder("utf-8").decode(new Uint8Array(bytes));
return JSON.parse(decodedString); return JSON.parse(decodedString);
} catch { } catch {

104
tests/algorithms.spec.ts Normal file
View File

@@ -0,0 +1,104 @@
import { describe, expect, test } from 'vitest'
import jwt, { JwtAlgorithm } from '../src/index'
type Dataset = {
public: string
private: string
token: string
}
type Data = {
[key in JwtAlgorithm]: Dataset
}
type Payload = {
sub: string
name: string
emoji: string
}
const data: Data = {
'ES256': {
public: '-----BEGIN PUBLIC KEY-----\nMFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAEEVs/o5+uQbTjL3chynL4wXgUg2R9\nq9UU8I5mEovUf86QZ7kOBIjJwqnzD1omageEHWwHdBO6B+dFabmdT9POxg==\n-----END PUBLIC KEY-----',
private: '-----BEGIN PRIVATE KEY-----\nMIGHAgEAMBMGByqGSM49AgEGCCqGSM49AwEHBG0wawIBAQQgevZzL1gdAFr88hb2\nOF/2NxApJCzGCEDdfSp6VQO30hyhRANCAAQRWz+jn65BtOMvdyHKcvjBeBSDZH2r\n1RTwjmYSi9R/zpBnuQ4EiMnCqfMPWiZqB4QdbAd0E7oH50VpuZ1P087G\n-----END PRIVATE KEY-----',
token: 'eyJhbGciOiJFUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiIxMjM0NTY3ODkwIiwibmFtZSI6IkpvaG4gRG9lIiwiaWF0IjoxNTE2MjM5MDIyfQ.Ri9u3ZJpyoHf1_i3KpVE5gMggyU3VMYPeEVktAsG1kGLOxFNJBXydQls3WFBaXXH2-sN74IMe-nDcM7NoJ6GMQ'
},
'ES384': {
public: '-----BEGIN PUBLIC KEY-----\nMHYwEAYHKoZIzj0CAQYFK4EEACIDYgAEC1uWSXj2czCDwMTLWV5BFmwxdM6PX9p+\nPk9Yf9rIf374m5XP1U8q79dBhLSIuaojsvOT39UUcPJROSD1FqYLued0rXiooIii\n1D3jaW6pmGVJFhodzC31cy5sfOYotrzF\n-----END PUBLIC KEY-----',
private: '-----BEGIN PRIVATE KEY-----\nMIG2AgEAMBAGByqGSM49AgEGBSuBBAAiBIGeMIGbAgEBBDCAHpFQ62QnGCEvYh/p\nE9QmR1C9aLcDItRbslbmhen/h1tt8AyMhskeenT+rAyyPhGhZANiAAQLW5ZJePZz\nMIPAxMtZXkEWbDF0zo9f2n4+T1h/2sh/fviblc/VTyrv10GEtIi5qiOy85Pf1RRw\n8lE5IPUWpgu553SteKigiKLUPeNpbqmYZUkWGh3MLfVzLmx85ii2vMU=\n-----END PRIVATE KEY-----',
token: 'eyJhbGciOiJFUzM4NCIsInR5cCI6IkpXVCJ9.eyJzdWIiOiIxMjM0NTY3ODkwIiwibmFtZSI6IkpvaG4gRG9lIiwiaWF0IjoxNTE2MjM5MDIyfQ.6nmlvcCpsfENb6ssgX3rJ2XSjpFSXD1RPS1CK0iDZFdi6I6Gnmpi456RSW6-0XSSgq2E2XBcWCSYE6TeI63jOGZJTQ6-65g4sndbzBPqYPWbLny00NQ4MQgQXVu6tRzg'
},
'ES512': {
public: '-----BEGIN PUBLIC KEY-----\nMIGbMBAGByqGSM49AgEGBSuBBAAjA4GGAAQBgc4HZz+/fBbC7lmEww0AO3NK9wVZ\nPDZ0VEnsaUFLEYpTzb90nITtJUcPUbvOsdZIZ1Q8fnbquAYgxXL5UgHMoywAib47\n6MkyyYgPk0BXZq3mq4zImTRNuaU9slj9TVJ3ScT3L1bXwVuPJDzpr5GOFpaj+WwM\nAl8G7CqwoJOsW7Kddns=\n-----END PUBLIC KEY-----',
private: '-----BEGIN PRIVATE KEY-----\nMIHuAgEAMBAGByqGSM49AgEGBSuBBAAjBIHWMIHTAgEBBEIBiyAa7aRHFDCh2qga\n9sTUGINE5jHAFnmM8xWeT/uni5I4tNqhV5Xx0pDrmCV9mbroFtfEa0XVfKuMAxxf\nZ6LM/yKhgYkDgYYABAGBzgdnP798FsLuWYTDDQA7c0r3BVk8NnRUSexpQUsRilPN\nv3SchO0lRw9Ru86x1khnVDx+duq4BiDFcvlSAcyjLACJvjvoyTLJiA+TQFdmrear\njMiZNE25pT2yWP1NUndJxPcvVtfBW48kPOmvkY4WlqP5bAwCXwbsKrCgk6xbsp12\new==\n-----END PRIVATE KEY-----',
token: 'eyJhbGciOiJFUzUxMiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiIxMjM0NTY3ODkwIiwibmFtZSI6IkpvaG4gRG9lIiwiaWF0IjoxNTE2MjM5MDIyfQ.AbRwaCPJM2X3XjE2kInClHVGJNIcpL5C4a1ZrgwEM05RTryyNbazWRFbXAEDtHm8crvXpqw3a8JQwYDwvMyoOr4jAJ4RbhJitLgCGEzhKjvNy4xGrg3dV8gGEShFowgDfVz0KqHOX_Bc_DbyL-gtZPdfGTwT2upLkJE-lj47RStPDh0b'
},
'HS256': {
public: 'secret',
private: 'secret',
token: 'eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiIxMjM0NTY3ODkwIiwibmFtZSI6IkpvaG4gRG9lIiwiaWF0IjoxNTE2MjM5MDIyfQ.XbPfbIHMI6arZ3Y922BhjWgQzWXcXNrz0ogtVhfEd2o'
},
'HS384': {
public: 'secret',
private: 'secret',
token: 'eyJhbGciOiJIUzM4NCIsInR5cCI6IkpXVCJ9.eyJzdWIiOiIxMjM0NTY3ODkwIiwibmFtZSI6IkpvaG4gRG9lIiwiaWF0IjoxNTE2MjM5MDIyfQ.hO2sthNQUSfvI9ylUdMKDxcrm8jB3KL6Rtkd3FOskL-jVqYh2CK1es8FKCQO8_tW'
},
'HS512': {
public: 'secret',
private: 'secret',
token: 'eyJhbGciOiJIUzUxMiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiIxMjM0NTY3ODkwIiwibmFtZSI6IkpvaG4gRG9lIiwiaWF0IjoxNTE2MjM5MDIyfQ.wUVS6tazE2N98_J4SH_djkEe1igXPu0qILAvVXCiO6O20gdf5vZ2sYFWX3c-Hy6L4TD47b3DSAAO9XjSqpJfag'
},
'RS256': {
public: '-----BEGIN PUBLIC KEY-----\nMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAu1SU1LfVLPHCozMxH2Mo\n4lgOEePzNm0tRgeLezV6ffAt0gunVTLw7onLRnrq0/IzW7yWR7QkrmBL7jTKEn5u\n+qKhbwKfBstIs+bMY2Zkp18gnTxKLxoS2tFczGkPLPgizskuemMghRniWaoLcyeh\nkd3qqGElvW/VDL5AaWTg0nLVkjRo9z+40RQzuVaE8AkAFmxZzow3x+VJYKdjykkJ\n0iT9wCS0DRTXu269V264Vf/3jvredZiKRkgwlL9xNAwxXFg0x/XFw005UWVRIkdg\ncKWTjpBP2dPwVZ4WWC+9aGVd+Gyn1o0CLelf4rEjGoXbAAEgAqeGUxrcIlbjXfbc\nmwIDAQAB\n-----END PUBLIC KEY-----',
private: '-----BEGIN PRIVATE KEY-----\nMIIEvwIBADANBgkqhkiG9w0BAQEFAASCBKkwggSlAgEAAoIBAQC7VJTUt9Us8cKj\nMzEfYyjiWA4R4/M2bS1GB4t7NXp98C3SC6dVMvDuictGeurT8jNbvJZHtCSuYEvu\nNMoSfm76oqFvAp8Gy0iz5sxjZmSnXyCdPEovGhLa0VzMaQ8s+CLOyS56YyCFGeJZ\nqgtzJ6GR3eqoYSW9b9UMvkBpZODSctWSNGj3P7jRFDO5VoTwCQAWbFnOjDfH5Ulg\np2PKSQnSJP3AJLQNFNe7br1XbrhV//eO+t51mIpGSDCUv3E0DDFcWDTH9cXDTTlR\nZVEiR2BwpZOOkE/Z0/BVnhZYL71oZV34bKfWjQIt6V/isSMahdsAASACp4ZTGtwi\nVuNd9tybAgMBAAECggEBAKTmjaS6tkK8BlPXClTQ2vpz/N6uxDeS35mXpqasqskV\nlaAidgg/sWqpjXDbXr93otIMLlWsM+X0CqMDgSXKejLS2jx4GDjI1ZTXg++0AMJ8\nsJ74pWzVDOfmCEQ/7wXs3+cbnXhKriO8Z036q92Qc1+N87SI38nkGa0ABH9CN83H\nmQqt4fB7UdHzuIRe/me2PGhIq5ZBzj6h3BpoPGzEP+x3l9YmK8t/1cN0pqI+dQwY\ndgfGjackLu/2qH80MCF7IyQaseZUOJyKrCLtSD/Iixv/hzDEUPfOCjFDgTpzf3cw\nta8+oE4wHCo1iI1/4TlPkwmXx4qSXtmw4aQPz7IDQvECgYEA8KNThCO2gsC2I9PQ\nDM/8Cw0O983WCDY+oi+7JPiNAJwv5DYBqEZB1QYdj06YD16XlC/HAZMsMku1na2T\nN0driwenQQWzoev3g2S7gRDoS/FCJSI3jJ+kjgtaA7Qmzlgk1TxODN+G1H91HW7t\n0l7VnL27IWyYo2qRRK3jzxqUiPUCgYEAx0oQs2reBQGMVZnApD1jeq7n4MvNLcPv\nt8b/eU9iUv6Y4Mj0Suo/AU8lYZXm8ubbqAlwz2VSVunD2tOplHyMUrtCtObAfVDU\nAhCndKaA9gApgfb3xw1IKbuQ1u4IF1FJl3VtumfQn//LiH1B3rXhcdyo3/vIttEk\n48RakUKClU8CgYEAzV7W3COOlDDcQd935DdtKBFRAPRPAlspQUnzMi5eSHMD/ISL\nDY5IiQHbIH83D4bvXq0X7qQoSBSNP7Dvv3HYuqMhf0DaegrlBuJllFVVq9qPVRnK\nxt1Il2HgxOBvbhOT+9in1BzA+YJ99UzC85O0Qz06A+CmtHEy4aZ2kj5hHjECgYEA\nmNS4+A8Fkss8Js1RieK2LniBxMgmYml3pfVLKGnzmng7H2+cwPLhPIzIuwytXywh\n2bzbsYEfYx3EoEVgMEpPhoarQnYPukrJO4gwE2o5Te6T5mJSZGlQJQj9q4ZB2Dfz\net6INsK0oG8XVGXSpQvQh3RUYekCZQkBBFcpqWpbIEsCgYAnM3DQf3FJoSnXaMhr\nVBIovic5l0xFkEHskAjFTevO86Fsz1C2aSeRKSqGFoOQ0tmJzBEs1R6KqnHInicD\nTQrKhArgLXX4v3CddjfTRJkFWDbE/CkvKZNOrcf1nhaGCPspRJj2KUkj1Fhl9Cnc\ndn/RsYEONbwQSjIfMPkvxF+8HQ==\n-----END PRIVATE KEY-----',
token: 'eyJhbGciOiJSUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiIxMjM0NTY3ODkwIiwibmFtZSI6IkpvaG4gRG9lIiwiaWF0IjoxNTE2MjM5MDIyfQ.Eci61G6w4zh_u9oOCk_v1M_sKcgk0svOmW4ZsL-rt4ojGUH2QY110bQTYNwbEVlowW7phCg7vluX_MCKVwJkxJT6tMk2Ij3Plad96Jf2G2mMsKbxkC-prvjvQkBFYWrYnKWClPBRCyIcG0dVfBvqZ8Mro3t5bX59IKwQ3WZ7AtGBYz5BSiBlrKkp6J1UmP_bFV3eEzIHEFgzRa3pbr4ol4TK6SnAoF88rLr2NhEz9vpdHglUMlOBQiqcZwqrI-Z4XDyDzvnrpujIToiepq9bCimPgVkP54VoZzy-mMSGbthYpLqsL_4MQXaI1Uf_wKFAUuAtzVn4-ebgsKOpvKNzVA'
},
'RS384': {
public: '-----BEGIN PUBLIC KEY-----\nMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAu1SU1LfVLPHCozMxH2Mo\n4lgOEePzNm0tRgeLezV6ffAt0gunVTLw7onLRnrq0/IzW7yWR7QkrmBL7jTKEn5u\n+qKhbwKfBstIs+bMY2Zkp18gnTxKLxoS2tFczGkPLPgizskuemMghRniWaoLcyeh\nkd3qqGElvW/VDL5AaWTg0nLVkjRo9z+40RQzuVaE8AkAFmxZzow3x+VJYKdjykkJ\n0iT9wCS0DRTXu269V264Vf/3jvredZiKRkgwlL9xNAwxXFg0x/XFw005UWVRIkdg\ncKWTjpBP2dPwVZ4WWC+9aGVd+Gyn1o0CLelf4rEjGoXbAAEgAqeGUxrcIlbjXfbc\nmwIDAQAB\n-----END PUBLIC KEY-----',
private: '-----BEGIN PRIVATE KEY-----\nMIIEvwIBADANBgkqhkiG9w0BAQEFAASCBKkwggSlAgEAAoIBAQC7VJTUt9Us8cKj\nMzEfYyjiWA4R4/M2bS1GB4t7NXp98C3SC6dVMvDuictGeurT8jNbvJZHtCSuYEvu\nNMoSfm76oqFvAp8Gy0iz5sxjZmSnXyCdPEovGhLa0VzMaQ8s+CLOyS56YyCFGeJZ\nqgtzJ6GR3eqoYSW9b9UMvkBpZODSctWSNGj3P7jRFDO5VoTwCQAWbFnOjDfH5Ulg\np2PKSQnSJP3AJLQNFNe7br1XbrhV//eO+t51mIpGSDCUv3E0DDFcWDTH9cXDTTlR\nZVEiR2BwpZOOkE/Z0/BVnhZYL71oZV34bKfWjQIt6V/isSMahdsAASACp4ZTGtwi\nVuNd9tybAgMBAAECggEBAKTmjaS6tkK8BlPXClTQ2vpz/N6uxDeS35mXpqasqskV\nlaAidgg/sWqpjXDbXr93otIMLlWsM+X0CqMDgSXKejLS2jx4GDjI1ZTXg++0AMJ8\nsJ74pWzVDOfmCEQ/7wXs3+cbnXhKriO8Z036q92Qc1+N87SI38nkGa0ABH9CN83H\nmQqt4fB7UdHzuIRe/me2PGhIq5ZBzj6h3BpoPGzEP+x3l9YmK8t/1cN0pqI+dQwY\ndgfGjackLu/2qH80MCF7IyQaseZUOJyKrCLtSD/Iixv/hzDEUPfOCjFDgTpzf3cw\nta8+oE4wHCo1iI1/4TlPkwmXx4qSXtmw4aQPz7IDQvECgYEA8KNThCO2gsC2I9PQ\nDM/8Cw0O983WCDY+oi+7JPiNAJwv5DYBqEZB1QYdj06YD16XlC/HAZMsMku1na2T\nN0driwenQQWzoev3g2S7gRDoS/FCJSI3jJ+kjgtaA7Qmzlgk1TxODN+G1H91HW7t\n0l7VnL27IWyYo2qRRK3jzxqUiPUCgYEAx0oQs2reBQGMVZnApD1jeq7n4MvNLcPv\nt8b/eU9iUv6Y4Mj0Suo/AU8lYZXm8ubbqAlwz2VSVunD2tOplHyMUrtCtObAfVDU\nAhCndKaA9gApgfb3xw1IKbuQ1u4IF1FJl3VtumfQn//LiH1B3rXhcdyo3/vIttEk\n48RakUKClU8CgYEAzV7W3COOlDDcQd935DdtKBFRAPRPAlspQUnzMi5eSHMD/ISL\nDY5IiQHbIH83D4bvXq0X7qQoSBSNP7Dvv3HYuqMhf0DaegrlBuJllFVVq9qPVRnK\nxt1Il2HgxOBvbhOT+9in1BzA+YJ99UzC85O0Qz06A+CmtHEy4aZ2kj5hHjECgYEA\nmNS4+A8Fkss8Js1RieK2LniBxMgmYml3pfVLKGnzmng7H2+cwPLhPIzIuwytXywh\n2bzbsYEfYx3EoEVgMEpPhoarQnYPukrJO4gwE2o5Te6T5mJSZGlQJQj9q4ZB2Dfz\net6INsK0oG8XVGXSpQvQh3RUYekCZQkBBFcpqWpbIEsCgYAnM3DQf3FJoSnXaMhr\nVBIovic5l0xFkEHskAjFTevO86Fsz1C2aSeRKSqGFoOQ0tmJzBEs1R6KqnHInicD\nTQrKhArgLXX4v3CddjfTRJkFWDbE/CkvKZNOrcf1nhaGCPspRJj2KUkj1Fhl9Cnc\ndn/RsYEONbwQSjIfMPkvxF+8HQ==\n-----END PRIVATE KEY-----',
token: 'eyJhbGciOiJSUzM4NCIsInR5cCI6IkpXVCJ9.eyJzdWIiOiIxMjM0NTY3ODkwIiwibmFtZSI6IkpvaG4gRG9lIiwiaWF0IjoxNTE2MjM5MDIyfQ.oPvWzaCp8xUpt5mHhPSn0qLsZfCFj0NVmb4mz4dFQPCCMj-F5zVn9e3zZoj0lIXWM8rxB69QHC3Er47mtDt3BKgysTL3BvvV89kD6UjLoUcAI3lwj0mi7acLoE27i1_TnIBqWNRPAsdvTDawNE0_4lvI5bxEWQCqisJwxCoMDIeJsmDzfyApgU_SAFSVULxXwU2VewaxdQB-41OZdWwUEAxh81iB6DFWrqd2CaJkUYoWjgYpeWsyeC2m_-ECGrHGEz1nKTm9c7BaPxurz7fHD7RJd9Wpx-mKDVsfspO9quWb_OLeGGbxTtAomMvjQjut56kx2fqTleDnNDh_0GE88w'
},
'RS512': {
public: '-----BEGIN PUBLIC KEY-----\nMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAu1SU1LfVLPHCozMxH2Mo\n4lgOEePzNm0tRgeLezV6ffAt0gunVTLw7onLRnrq0/IzW7yWR7QkrmBL7jTKEn5u\n+qKhbwKfBstIs+bMY2Zkp18gnTxKLxoS2tFczGkPLPgizskuemMghRniWaoLcyeh\nkd3qqGElvW/VDL5AaWTg0nLVkjRo9z+40RQzuVaE8AkAFmxZzow3x+VJYKdjykkJ\n0iT9wCS0DRTXu269V264Vf/3jvredZiKRkgwlL9xNAwxXFg0x/XFw005UWVRIkdg\ncKWTjpBP2dPwVZ4WWC+9aGVd+Gyn1o0CLelf4rEjGoXbAAEgAqeGUxrcIlbjXfbc\nmwIDAQAB\n-----END PUBLIC KEY-----',
private: '-----BEGIN PRIVATE KEY-----\nMIIEvwIBADANBgkqhkiG9w0BAQEFAASCBKkwggSlAgEAAoIBAQC7VJTUt9Us8cKj\nMzEfYyjiWA4R4/M2bS1GB4t7NXp98C3SC6dVMvDuictGeurT8jNbvJZHtCSuYEvu\nNMoSfm76oqFvAp8Gy0iz5sxjZmSnXyCdPEovGhLa0VzMaQ8s+CLOyS56YyCFGeJZ\nqgtzJ6GR3eqoYSW9b9UMvkBpZODSctWSNGj3P7jRFDO5VoTwCQAWbFnOjDfH5Ulg\np2PKSQnSJP3AJLQNFNe7br1XbrhV//eO+t51mIpGSDCUv3E0DDFcWDTH9cXDTTlR\nZVEiR2BwpZOOkE/Z0/BVnhZYL71oZV34bKfWjQIt6V/isSMahdsAASACp4ZTGtwi\nVuNd9tybAgMBAAECggEBAKTmjaS6tkK8BlPXClTQ2vpz/N6uxDeS35mXpqasqskV\nlaAidgg/sWqpjXDbXr93otIMLlWsM+X0CqMDgSXKejLS2jx4GDjI1ZTXg++0AMJ8\nsJ74pWzVDOfmCEQ/7wXs3+cbnXhKriO8Z036q92Qc1+N87SI38nkGa0ABH9CN83H\nmQqt4fB7UdHzuIRe/me2PGhIq5ZBzj6h3BpoPGzEP+x3l9YmK8t/1cN0pqI+dQwY\ndgfGjackLu/2qH80MCF7IyQaseZUOJyKrCLtSD/Iixv/hzDEUPfOCjFDgTpzf3cw\nta8+oE4wHCo1iI1/4TlPkwmXx4qSXtmw4aQPz7IDQvECgYEA8KNThCO2gsC2I9PQ\nDM/8Cw0O983WCDY+oi+7JPiNAJwv5DYBqEZB1QYdj06YD16XlC/HAZMsMku1na2T\nN0driwenQQWzoev3g2S7gRDoS/FCJSI3jJ+kjgtaA7Qmzlgk1TxODN+G1H91HW7t\n0l7VnL27IWyYo2qRRK3jzxqUiPUCgYEAx0oQs2reBQGMVZnApD1jeq7n4MvNLcPv\nt8b/eU9iUv6Y4Mj0Suo/AU8lYZXm8ubbqAlwz2VSVunD2tOplHyMUrtCtObAfVDU\nAhCndKaA9gApgfb3xw1IKbuQ1u4IF1FJl3VtumfQn//LiH1B3rXhcdyo3/vIttEk\n48RakUKClU8CgYEAzV7W3COOlDDcQd935DdtKBFRAPRPAlspQUnzMi5eSHMD/ISL\nDY5IiQHbIH83D4bvXq0X7qQoSBSNP7Dvv3HYuqMhf0DaegrlBuJllFVVq9qPVRnK\nxt1Il2HgxOBvbhOT+9in1BzA+YJ99UzC85O0Qz06A+CmtHEy4aZ2kj5hHjECgYEA\nmNS4+A8Fkss8Js1RieK2LniBxMgmYml3pfVLKGnzmng7H2+cwPLhPIzIuwytXywh\n2bzbsYEfYx3EoEVgMEpPhoarQnYPukrJO4gwE2o5Te6T5mJSZGlQJQj9q4ZB2Dfz\net6INsK0oG8XVGXSpQvQh3RUYekCZQkBBFcpqWpbIEsCgYAnM3DQf3FJoSnXaMhr\nVBIovic5l0xFkEHskAjFTevO86Fsz1C2aSeRKSqGFoOQ0tmJzBEs1R6KqnHInicD\nTQrKhArgLXX4v3CddjfTRJkFWDbE/CkvKZNOrcf1nhaGCPspRJj2KUkj1Fhl9Cnc\ndn/RsYEONbwQSjIfMPkvxF+8HQ==\n-----END PRIVATE KEY-----',
token: 'eyJhbGciOiJSUzUxMiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiIxMjM0NTY3ODkwIiwibmFtZSI6IkpvaG4gRG9lIiwiaWF0IjoxNTE2MjM5MDIyfQ.kEZmDAnHHU_0bcGXMd5LA7vF87yQgXNaioPHP4lU4O3JJYuZ54fJdv3HT58xk-MFEDuWro_5fvNIp2VM-PlkZvYWrhQkJ-c-seoSa3ANq_PciC3bGfzYHEdjAE71GrAMI4FlcAGsq3ChkOnCTFqjWDmVwaRYCgMsFQ-U5cjvFhndFMizrkRljTF4v5oFdWytV_J-UafPtNdQXcGND1M74DqObnTHhZHg8aDfNzZcvnIeKcDVGUlUEL5ia1kPMrVhCtOAOJmEU8ivCdWWzt-jMQBf7cZeoCzDKHG72ysTTCfRoBVc1_SrQTHcHDiiBeW9nCazMLkltyP5NeawR_RNlg'
}
}
const payload: Payload = {
sub: "1234567890",
name: "John Doe",
emoji: "😎"
}
const jwtRegex = /^[a-zA-Z0-9\-_]+\.[a-zA-Z0-9\-_]+\.[a-zA-Z0-9\-_]+$/
describe("Internal", () => {
test.each(Object.entries(data) as [JwtAlgorithm, Dataset][])('%s', async (algorithm, data) => {
const token = await jwt.sign<Payload>(payload, data.private, algorithm)
expect(token).toMatch(jwtRegex)
const decoded = jwt.decode<Payload>(token)
expect(decoded.payload).toMatchObject(payload)
const verified = await jwt.verify(token, data.public, algorithm)
expect(verified).toBe(true)
})
})
describe("External", async () => {
test.each(Object.entries(data) as [JwtAlgorithm, Dataset][])('%s', async (algorithm, data) => {
const decoded = jwt.decode<Payload>(data.token)
expect({
sub: decoded.payload?.sub,
name: decoded.payload?.name,
}).toMatchObject({
sub: payload.sub,
name: payload.name
})
const verified = await jwt.verify(data.token, data.public, algorithm)
expect(verified).toBe(true)
})
})

View File

@@ -1,148 +1,39 @@
import { describe, expect, test } from 'vitest' import { describe, expect, test } from "vitest"
import jwt, { JwtAlgorithm } from '../src/index' import jwt from "../src/index"
type Dataset = { describe("Verify", async () => {
public: string const secret = "super-secret"
private: string
token: string
}
type Data = {
[key in JwtAlgorithm]: Dataset
}
type Payload = {
sub: string
name: string
}
const data: Data = {
'ES256': {
public: '-----BEGIN PUBLIC KEY-----\nMFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAEEVs/o5+uQbTjL3chynL4wXgUg2R9\nq9UU8I5mEovUf86QZ7kOBIjJwqnzD1omageEHWwHdBO6B+dFabmdT9POxg==\n-----END PUBLIC KEY-----',
private: '-----BEGIN PRIVATE KEY-----\nMIGHAgEAMBMGByqGSM49AgEGCCqGSM49AwEHBG0wawIBAQQgevZzL1gdAFr88hb2\nOF/2NxApJCzGCEDdfSp6VQO30hyhRANCAAQRWz+jn65BtOMvdyHKcvjBeBSDZH2r\n1RTwjmYSi9R/zpBnuQ4EiMnCqfMPWiZqB4QdbAd0E7oH50VpuZ1P087G\n-----END PRIVATE KEY-----',
token: 'eyJhbGciOiJFUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiIxMjM0NTY3ODkwIiwibmFtZSI6IkpvaG4gRG9lIiwiaWF0IjoxNTE2MjM5MDIyfQ.Ri9u3ZJpyoHf1_i3KpVE5gMggyU3VMYPeEVktAsG1kGLOxFNJBXydQls3WFBaXXH2-sN74IMe-nDcM7NoJ6GMQ'
},
'ES384': {
public: '-----BEGIN PUBLIC KEY-----\nMHYwEAYHKoZIzj0CAQYFK4EEACIDYgAEC1uWSXj2czCDwMTLWV5BFmwxdM6PX9p+\nPk9Yf9rIf374m5XP1U8q79dBhLSIuaojsvOT39UUcPJROSD1FqYLued0rXiooIii\n1D3jaW6pmGVJFhodzC31cy5sfOYotrzF\n-----END PUBLIC KEY-----',
private: '-----BEGIN PRIVATE KEY-----\nMIG2AgEAMBAGByqGSM49AgEGBSuBBAAiBIGeMIGbAgEBBDCAHpFQ62QnGCEvYh/p\nE9QmR1C9aLcDItRbslbmhen/h1tt8AyMhskeenT+rAyyPhGhZANiAAQLW5ZJePZz\nMIPAxMtZXkEWbDF0zo9f2n4+T1h/2sh/fviblc/VTyrv10GEtIi5qiOy85Pf1RRw\n8lE5IPUWpgu553SteKigiKLUPeNpbqmYZUkWGh3MLfVzLmx85ii2vMU=\n-----END PRIVATE KEY-----',
token: 'eyJhbGciOiJFUzM4NCIsInR5cCI6IkpXVCJ9.eyJzdWIiOiIxMjM0NTY3ODkwIiwibmFtZSI6IkpvaG4gRG9lIiwiaWF0IjoxNTE2MjM5MDIyfQ.6nmlvcCpsfENb6ssgX3rJ2XSjpFSXD1RPS1CK0iDZFdi6I6Gnmpi456RSW6-0XSSgq2E2XBcWCSYE6TeI63jOGZJTQ6-65g4sndbzBPqYPWbLny00NQ4MQgQXVu6tRzg'
},
'ES512': {
public: '-----BEGIN PUBLIC KEY-----\nMIGbMBAGByqGSM49AgEGBSuBBAAjA4GGAAQBgc4HZz+/fBbC7lmEww0AO3NK9wVZ\nPDZ0VEnsaUFLEYpTzb90nITtJUcPUbvOsdZIZ1Q8fnbquAYgxXL5UgHMoywAib47\n6MkyyYgPk0BXZq3mq4zImTRNuaU9slj9TVJ3ScT3L1bXwVuPJDzpr5GOFpaj+WwM\nAl8G7CqwoJOsW7Kddns=\n-----END PUBLIC KEY-----',
private: '-----BEGIN PRIVATE KEY-----\nMIHuAgEAMBAGByqGSM49AgEGBSuBBAAjBIHWMIHTAgEBBEIBiyAa7aRHFDCh2qga\n9sTUGINE5jHAFnmM8xWeT/uni5I4tNqhV5Xx0pDrmCV9mbroFtfEa0XVfKuMAxxf\nZ6LM/yKhgYkDgYYABAGBzgdnP798FsLuWYTDDQA7c0r3BVk8NnRUSexpQUsRilPN\nv3SchO0lRw9Ru86x1khnVDx+duq4BiDFcvlSAcyjLACJvjvoyTLJiA+TQFdmrear\njMiZNE25pT2yWP1NUndJxPcvVtfBW48kPOmvkY4WlqP5bAwCXwbsKrCgk6xbsp12\new==\n-----END PRIVATE KEY-----',
token: 'eyJhbGciOiJFUzUxMiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiIxMjM0NTY3ODkwIiwibmFtZSI6IkpvaG4gRG9lIiwiaWF0IjoxNTE2MjM5MDIyfQ.AbRwaCPJM2X3XjE2kInClHVGJNIcpL5C4a1ZrgwEM05RTryyNbazWRFbXAEDtHm8crvXpqw3a8JQwYDwvMyoOr4jAJ4RbhJitLgCGEzhKjvNy4xGrg3dV8gGEShFowgDfVz0KqHOX_Bc_DbyL-gtZPdfGTwT2upLkJE-lj47RStPDh0b'
},
'HS256': {
public: 'secret',
private: 'secret',
token: 'eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiIxMjM0NTY3ODkwIiwibmFtZSI6IkpvaG4gRG9lIiwiaWF0IjoxNTE2MjM5MDIyfQ.XbPfbIHMI6arZ3Y922BhjWgQzWXcXNrz0ogtVhfEd2o'
},
'HS384': {
public: 'secret',
private: 'secret',
token: 'eyJhbGciOiJIUzM4NCIsInR5cCI6IkpXVCJ9.eyJzdWIiOiIxMjM0NTY3ODkwIiwibmFtZSI6IkpvaG4gRG9lIiwiaWF0IjoxNTE2MjM5MDIyfQ.hO2sthNQUSfvI9ylUdMKDxcrm8jB3KL6Rtkd3FOskL-jVqYh2CK1es8FKCQO8_tW'
},
'HS512': {
public: 'secret',
private: 'secret',
token: 'eyJhbGciOiJIUzUxMiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiIxMjM0NTY3ODkwIiwibmFtZSI6IkpvaG4gRG9lIiwiaWF0IjoxNTE2MjM5MDIyfQ.wUVS6tazE2N98_J4SH_djkEe1igXPu0qILAvVXCiO6O20gdf5vZ2sYFWX3c-Hy6L4TD47b3DSAAO9XjSqpJfag'
},
'RS256': {
public: '-----BEGIN PUBLIC KEY-----\nMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAu1SU1LfVLPHCozMxH2Mo\n4lgOEePzNm0tRgeLezV6ffAt0gunVTLw7onLRnrq0/IzW7yWR7QkrmBL7jTKEn5u\n+qKhbwKfBstIs+bMY2Zkp18gnTxKLxoS2tFczGkPLPgizskuemMghRniWaoLcyeh\nkd3qqGElvW/VDL5AaWTg0nLVkjRo9z+40RQzuVaE8AkAFmxZzow3x+VJYKdjykkJ\n0iT9wCS0DRTXu269V264Vf/3jvredZiKRkgwlL9xNAwxXFg0x/XFw005UWVRIkdg\ncKWTjpBP2dPwVZ4WWC+9aGVd+Gyn1o0CLelf4rEjGoXbAAEgAqeGUxrcIlbjXfbc\nmwIDAQAB\n-----END PUBLIC KEY-----',
private: '-----BEGIN PRIVATE KEY-----\nMIIEvwIBADANBgkqhkiG9w0BAQEFAASCBKkwggSlAgEAAoIBAQC7VJTUt9Us8cKj\nMzEfYyjiWA4R4/M2bS1GB4t7NXp98C3SC6dVMvDuictGeurT8jNbvJZHtCSuYEvu\nNMoSfm76oqFvAp8Gy0iz5sxjZmSnXyCdPEovGhLa0VzMaQ8s+CLOyS56YyCFGeJZ\nqgtzJ6GR3eqoYSW9b9UMvkBpZODSctWSNGj3P7jRFDO5VoTwCQAWbFnOjDfH5Ulg\np2PKSQnSJP3AJLQNFNe7br1XbrhV//eO+t51mIpGSDCUv3E0DDFcWDTH9cXDTTlR\nZVEiR2BwpZOOkE/Z0/BVnhZYL71oZV34bKfWjQIt6V/isSMahdsAASACp4ZTGtwi\nVuNd9tybAgMBAAECggEBAKTmjaS6tkK8BlPXClTQ2vpz/N6uxDeS35mXpqasqskV\nlaAidgg/sWqpjXDbXr93otIMLlWsM+X0CqMDgSXKejLS2jx4GDjI1ZTXg++0AMJ8\nsJ74pWzVDOfmCEQ/7wXs3+cbnXhKriO8Z036q92Qc1+N87SI38nkGa0ABH9CN83H\nmQqt4fB7UdHzuIRe/me2PGhIq5ZBzj6h3BpoPGzEP+x3l9YmK8t/1cN0pqI+dQwY\ndgfGjackLu/2qH80MCF7IyQaseZUOJyKrCLtSD/Iixv/hzDEUPfOCjFDgTpzf3cw\nta8+oE4wHCo1iI1/4TlPkwmXx4qSXtmw4aQPz7IDQvECgYEA8KNThCO2gsC2I9PQ\nDM/8Cw0O983WCDY+oi+7JPiNAJwv5DYBqEZB1QYdj06YD16XlC/HAZMsMku1na2T\nN0driwenQQWzoev3g2S7gRDoS/FCJSI3jJ+kjgtaA7Qmzlgk1TxODN+G1H91HW7t\n0l7VnL27IWyYo2qRRK3jzxqUiPUCgYEAx0oQs2reBQGMVZnApD1jeq7n4MvNLcPv\nt8b/eU9iUv6Y4Mj0Suo/AU8lYZXm8ubbqAlwz2VSVunD2tOplHyMUrtCtObAfVDU\nAhCndKaA9gApgfb3xw1IKbuQ1u4IF1FJl3VtumfQn//LiH1B3rXhcdyo3/vIttEk\n48RakUKClU8CgYEAzV7W3COOlDDcQd935DdtKBFRAPRPAlspQUnzMi5eSHMD/ISL\nDY5IiQHbIH83D4bvXq0X7qQoSBSNP7Dvv3HYuqMhf0DaegrlBuJllFVVq9qPVRnK\nxt1Il2HgxOBvbhOT+9in1BzA+YJ99UzC85O0Qz06A+CmtHEy4aZ2kj5hHjECgYEA\nmNS4+A8Fkss8Js1RieK2LniBxMgmYml3pfVLKGnzmng7H2+cwPLhPIzIuwytXywh\n2bzbsYEfYx3EoEVgMEpPhoarQnYPukrJO4gwE2o5Te6T5mJSZGlQJQj9q4ZB2Dfz\net6INsK0oG8XVGXSpQvQh3RUYekCZQkBBFcpqWpbIEsCgYAnM3DQf3FJoSnXaMhr\nVBIovic5l0xFkEHskAjFTevO86Fsz1C2aSeRKSqGFoOQ0tmJzBEs1R6KqnHInicD\nTQrKhArgLXX4v3CddjfTRJkFWDbE/CkvKZNOrcf1nhaGCPspRJj2KUkj1Fhl9Cnc\ndn/RsYEONbwQSjIfMPkvxF+8HQ==\n-----END PRIVATE KEY-----',
token: 'eyJhbGciOiJSUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiIxMjM0NTY3ODkwIiwibmFtZSI6IkpvaG4gRG9lIiwiaWF0IjoxNTE2MjM5MDIyfQ.Eci61G6w4zh_u9oOCk_v1M_sKcgk0svOmW4ZsL-rt4ojGUH2QY110bQTYNwbEVlowW7phCg7vluX_MCKVwJkxJT6tMk2Ij3Plad96Jf2G2mMsKbxkC-prvjvQkBFYWrYnKWClPBRCyIcG0dVfBvqZ8Mro3t5bX59IKwQ3WZ7AtGBYz5BSiBlrKkp6J1UmP_bFV3eEzIHEFgzRa3pbr4ol4TK6SnAoF88rLr2NhEz9vpdHglUMlOBQiqcZwqrI-Z4XDyDzvnrpujIToiepq9bCimPgVkP54VoZzy-mMSGbthYpLqsL_4MQXaI1Uf_wKFAUuAtzVn4-ebgsKOpvKNzVA'
},
'RS384': {
public: '-----BEGIN PUBLIC KEY-----\nMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAu1SU1LfVLPHCozMxH2Mo\n4lgOEePzNm0tRgeLezV6ffAt0gunVTLw7onLRnrq0/IzW7yWR7QkrmBL7jTKEn5u\n+qKhbwKfBstIs+bMY2Zkp18gnTxKLxoS2tFczGkPLPgizskuemMghRniWaoLcyeh\nkd3qqGElvW/VDL5AaWTg0nLVkjRo9z+40RQzuVaE8AkAFmxZzow3x+VJYKdjykkJ\n0iT9wCS0DRTXu269V264Vf/3jvredZiKRkgwlL9xNAwxXFg0x/XFw005UWVRIkdg\ncKWTjpBP2dPwVZ4WWC+9aGVd+Gyn1o0CLelf4rEjGoXbAAEgAqeGUxrcIlbjXfbc\nmwIDAQAB\n-----END PUBLIC KEY-----',
private: '-----BEGIN PRIVATE KEY-----\nMIIEvwIBADANBgkqhkiG9w0BAQEFAASCBKkwggSlAgEAAoIBAQC7VJTUt9Us8cKj\nMzEfYyjiWA4R4/M2bS1GB4t7NXp98C3SC6dVMvDuictGeurT8jNbvJZHtCSuYEvu\nNMoSfm76oqFvAp8Gy0iz5sxjZmSnXyCdPEovGhLa0VzMaQ8s+CLOyS56YyCFGeJZ\nqgtzJ6GR3eqoYSW9b9UMvkBpZODSctWSNGj3P7jRFDO5VoTwCQAWbFnOjDfH5Ulg\np2PKSQnSJP3AJLQNFNe7br1XbrhV//eO+t51mIpGSDCUv3E0DDFcWDTH9cXDTTlR\nZVEiR2BwpZOOkE/Z0/BVnhZYL71oZV34bKfWjQIt6V/isSMahdsAASACp4ZTGtwi\nVuNd9tybAgMBAAECggEBAKTmjaS6tkK8BlPXClTQ2vpz/N6uxDeS35mXpqasqskV\nlaAidgg/sWqpjXDbXr93otIMLlWsM+X0CqMDgSXKejLS2jx4GDjI1ZTXg++0AMJ8\nsJ74pWzVDOfmCEQ/7wXs3+cbnXhKriO8Z036q92Qc1+N87SI38nkGa0ABH9CN83H\nmQqt4fB7UdHzuIRe/me2PGhIq5ZBzj6h3BpoPGzEP+x3l9YmK8t/1cN0pqI+dQwY\ndgfGjackLu/2qH80MCF7IyQaseZUOJyKrCLtSD/Iixv/hzDEUPfOCjFDgTpzf3cw\nta8+oE4wHCo1iI1/4TlPkwmXx4qSXtmw4aQPz7IDQvECgYEA8KNThCO2gsC2I9PQ\nDM/8Cw0O983WCDY+oi+7JPiNAJwv5DYBqEZB1QYdj06YD16XlC/HAZMsMku1na2T\nN0driwenQQWzoev3g2S7gRDoS/FCJSI3jJ+kjgtaA7Qmzlgk1TxODN+G1H91HW7t\n0l7VnL27IWyYo2qRRK3jzxqUiPUCgYEAx0oQs2reBQGMVZnApD1jeq7n4MvNLcPv\nt8b/eU9iUv6Y4Mj0Suo/AU8lYZXm8ubbqAlwz2VSVunD2tOplHyMUrtCtObAfVDU\nAhCndKaA9gApgfb3xw1IKbuQ1u4IF1FJl3VtumfQn//LiH1B3rXhcdyo3/vIttEk\n48RakUKClU8CgYEAzV7W3COOlDDcQd935DdtKBFRAPRPAlspQUnzMi5eSHMD/ISL\nDY5IiQHbIH83D4bvXq0X7qQoSBSNP7Dvv3HYuqMhf0DaegrlBuJllFVVq9qPVRnK\nxt1Il2HgxOBvbhOT+9in1BzA+YJ99UzC85O0Qz06A+CmtHEy4aZ2kj5hHjECgYEA\nmNS4+A8Fkss8Js1RieK2LniBxMgmYml3pfVLKGnzmng7H2+cwPLhPIzIuwytXywh\n2bzbsYEfYx3EoEVgMEpPhoarQnYPukrJO4gwE2o5Te6T5mJSZGlQJQj9q4ZB2Dfz\net6INsK0oG8XVGXSpQvQh3RUYekCZQkBBFcpqWpbIEsCgYAnM3DQf3FJoSnXaMhr\nVBIovic5l0xFkEHskAjFTevO86Fsz1C2aSeRKSqGFoOQ0tmJzBEs1R6KqnHInicD\nTQrKhArgLXX4v3CddjfTRJkFWDbE/CkvKZNOrcf1nhaGCPspRJj2KUkj1Fhl9Cnc\ndn/RsYEONbwQSjIfMPkvxF+8HQ==\n-----END PRIVATE KEY-----',
token: 'eyJhbGciOiJSUzM4NCIsInR5cCI6IkpXVCJ9.eyJzdWIiOiIxMjM0NTY3ODkwIiwibmFtZSI6IkpvaG4gRG9lIiwiaWF0IjoxNTE2MjM5MDIyfQ.oPvWzaCp8xUpt5mHhPSn0qLsZfCFj0NVmb4mz4dFQPCCMj-F5zVn9e3zZoj0lIXWM8rxB69QHC3Er47mtDt3BKgysTL3BvvV89kD6UjLoUcAI3lwj0mi7acLoE27i1_TnIBqWNRPAsdvTDawNE0_4lvI5bxEWQCqisJwxCoMDIeJsmDzfyApgU_SAFSVULxXwU2VewaxdQB-41OZdWwUEAxh81iB6DFWrqd2CaJkUYoWjgYpeWsyeC2m_-ECGrHGEz1nKTm9c7BaPxurz7fHD7RJd9Wpx-mKDVsfspO9quWb_OLeGGbxTtAomMvjQjut56kx2fqTleDnNDh_0GE88w'
},
'RS512': {
public: '-----BEGIN PUBLIC KEY-----\nMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAu1SU1LfVLPHCozMxH2Mo\n4lgOEePzNm0tRgeLezV6ffAt0gunVTLw7onLRnrq0/IzW7yWR7QkrmBL7jTKEn5u\n+qKhbwKfBstIs+bMY2Zkp18gnTxKLxoS2tFczGkPLPgizskuemMghRniWaoLcyeh\nkd3qqGElvW/VDL5AaWTg0nLVkjRo9z+40RQzuVaE8AkAFmxZzow3x+VJYKdjykkJ\n0iT9wCS0DRTXu269V264Vf/3jvredZiKRkgwlL9xNAwxXFg0x/XFw005UWVRIkdg\ncKWTjpBP2dPwVZ4WWC+9aGVd+Gyn1o0CLelf4rEjGoXbAAEgAqeGUxrcIlbjXfbc\nmwIDAQAB\n-----END PUBLIC KEY-----',
private: '-----BEGIN PRIVATE KEY-----\nMIIEvwIBADANBgkqhkiG9w0BAQEFAASCBKkwggSlAgEAAoIBAQC7VJTUt9Us8cKj\nMzEfYyjiWA4R4/M2bS1GB4t7NXp98C3SC6dVMvDuictGeurT8jNbvJZHtCSuYEvu\nNMoSfm76oqFvAp8Gy0iz5sxjZmSnXyCdPEovGhLa0VzMaQ8s+CLOyS56YyCFGeJZ\nqgtzJ6GR3eqoYSW9b9UMvkBpZODSctWSNGj3P7jRFDO5VoTwCQAWbFnOjDfH5Ulg\np2PKSQnSJP3AJLQNFNe7br1XbrhV//eO+t51mIpGSDCUv3E0DDFcWDTH9cXDTTlR\nZVEiR2BwpZOOkE/Z0/BVnhZYL71oZV34bKfWjQIt6V/isSMahdsAASACp4ZTGtwi\nVuNd9tybAgMBAAECggEBAKTmjaS6tkK8BlPXClTQ2vpz/N6uxDeS35mXpqasqskV\nlaAidgg/sWqpjXDbXr93otIMLlWsM+X0CqMDgSXKejLS2jx4GDjI1ZTXg++0AMJ8\nsJ74pWzVDOfmCEQ/7wXs3+cbnXhKriO8Z036q92Qc1+N87SI38nkGa0ABH9CN83H\nmQqt4fB7UdHzuIRe/me2PGhIq5ZBzj6h3BpoPGzEP+x3l9YmK8t/1cN0pqI+dQwY\ndgfGjackLu/2qH80MCF7IyQaseZUOJyKrCLtSD/Iixv/hzDEUPfOCjFDgTpzf3cw\nta8+oE4wHCo1iI1/4TlPkwmXx4qSXtmw4aQPz7IDQvECgYEA8KNThCO2gsC2I9PQ\nDM/8Cw0O983WCDY+oi+7JPiNAJwv5DYBqEZB1QYdj06YD16XlC/HAZMsMku1na2T\nN0driwenQQWzoev3g2S7gRDoS/FCJSI3jJ+kjgtaA7Qmzlgk1TxODN+G1H91HW7t\n0l7VnL27IWyYo2qRRK3jzxqUiPUCgYEAx0oQs2reBQGMVZnApD1jeq7n4MvNLcPv\nt8b/eU9iUv6Y4Mj0Suo/AU8lYZXm8ubbqAlwz2VSVunD2tOplHyMUrtCtObAfVDU\nAhCndKaA9gApgfb3xw1IKbuQ1u4IF1FJl3VtumfQn//LiH1B3rXhcdyo3/vIttEk\n48RakUKClU8CgYEAzV7W3COOlDDcQd935DdtKBFRAPRPAlspQUnzMi5eSHMD/ISL\nDY5IiQHbIH83D4bvXq0X7qQoSBSNP7Dvv3HYuqMhf0DaegrlBuJllFVVq9qPVRnK\nxt1Il2HgxOBvbhOT+9in1BzA+YJ99UzC85O0Qz06A+CmtHEy4aZ2kj5hHjECgYEA\nmNS4+A8Fkss8Js1RieK2LniBxMgmYml3pfVLKGnzmng7H2+cwPLhPIzIuwytXywh\n2bzbsYEfYx3EoEVgMEpPhoarQnYPukrJO4gwE2o5Te6T5mJSZGlQJQj9q4ZB2Dfz\net6INsK0oG8XVGXSpQvQh3RUYekCZQkBBFcpqWpbIEsCgYAnM3DQf3FJoSnXaMhr\nVBIovic5l0xFkEHskAjFTevO86Fsz1C2aSeRKSqGFoOQ0tmJzBEs1R6KqnHInicD\nTQrKhArgLXX4v3CddjfTRJkFWDbE/CkvKZNOrcf1nhaGCPspRJj2KUkj1Fhl9Cnc\ndn/RsYEONbwQSjIfMPkvxF+8HQ==\n-----END PRIVATE KEY-----',
token: 'eyJhbGciOiJSUzUxMiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiIxMjM0NTY3ODkwIiwibmFtZSI6IkpvaG4gRG9lIiwiaWF0IjoxNTE2MjM5MDIyfQ.kEZmDAnHHU_0bcGXMd5LA7vF87yQgXNaioPHP4lU4O3JJYuZ54fJdv3HT58xk-MFEDuWro_5fvNIp2VM-PlkZvYWrhQkJ-c-seoSa3ANq_PciC3bGfzYHEdjAE71GrAMI4FlcAGsq3ChkOnCTFqjWDmVwaRYCgMsFQ-U5cjvFhndFMizrkRljTF4v5oFdWytV_J-UafPtNdQXcGND1M74DqObnTHhZHg8aDfNzZcvnIeKcDVGUlUEL5ia1kPMrVhCtOAOJmEU8ivCdWWzt-jMQBf7cZeoCzDKHG72ysTTCfRoBVc1_SrQTHcHDiiBeW9nCazMLkltyP5NeawR_RNlg'
}
}
const payload: Payload = {
sub: "1234567890",
name: "John Doe",
}
const unicodePayload: Payload = {
sub: "1234567890",
name: "John Doe 😎",
}
describe.each(Object.entries(data) as [JwtAlgorithm, Dataset][])('%s', (algorithm, data) => {
let token = ''
test('verify external', async () => {
const verified = await jwt.verify(data.token, data.public, algorithm)
expect(verified).toBeTruthy()
})
test('decode external', async () => {
const decoded = jwt.decode<Payload>(data.token)
expect({
sub: payload.sub,
name: payload.name
}).toMatchObject({
sub: decoded.payload?.sub,
name: payload.name
})
})
test('sign internal', async () => {
token = await jwt.sign<Payload>(payload, data.private, algorithm)
expect(token).toMatch(/^[a-zA-Z0-9\-_]+\.[a-zA-Z0-9\-_]+\.[a-zA-Z0-9\-_]+$/)
})
test('sign unciode', async () => {
token = await jwt.sign<Payload>(unicodePayload, data.private, algorithm)
expect(token).toMatch(/^[a-zA-Z0-9\-_]+\.[a-zA-Z0-9\-_]+\.[a-zA-Z0-9\-_]+$/)
})
test('decode internal', async () => {
const decoded = jwt.decode(token)
expect({
sub: payload.sub,
name: payload.name
}).toMatchObject({
sub: decoded.payload?.sub,
name: payload.name
})
})
test('verify internal', async () => {
const verified = await jwt.verify(token, data.public, algorithm)
expect(verified).toBeTruthy()
})
})
describe('Verify', async () => {
const secret = 'super-secret'
const now = Math.floor(Date.now() / 1000) const now = Math.floor(Date.now() / 1000)
const off = 30 // 30 seconds const offset = 30 // 30 seconds
const nbf = now + off // Not valid before 30 seconds from now
const exp = now - off // Expired 30 seconds ago
const notYetValidToken = await jwt.sign({ sub: 'me', nbf }, secret) const validToken = await jwt.sign({ sub: "me", nbf: now - offset }, secret)
const expiredToken = await jwt.sign({ sub: 'me', exp }, secret) const notYetExpired = await jwt.sign({ sub: "me", exp: now + offset }, secret)
test('Not yet valid', () => { const notYetValidToken = await jwt.sign({ sub: "me", nbf: now + offset }, secret)
expect(jwt.verify(notYetValidToken, secret, { throwError: true })).rejects.toThrowError('NOT_YET_VALID') const expiredToken = await jwt.sign({ sub: "me", exp: now - offset }, secret)
test("Valid", () => {
expect(jwt.verify(validToken, secret, { throwError: true })).resolves.toBe(true)
}) })
test('Expired', () => { test("Not yet expired", () => {
console.log({ exp, now: Math.floor(Date.now() / 1000) }) expect(jwt.verify(notYetExpired, secret, { throwError: true })).resolves.toBe(true)
expect(jwt.verify(expiredToken, secret, { throwError: true })).rejects.toThrowError('EXPIRED')
}) })
test('Clock offset', () => { test("Not yet valid", () => {
expect(jwt.verify(notYetValidToken, secret, { clockTolerance: off, throwError: true })).resolves.toBe(true) expect(jwt.verify(notYetValidToken, secret, { throwError: true })).rejects.toThrowError("NOT_YET_VALID")
expect(jwt.verify(expiredToken, secret, { clockTolerance: off, throwError: true })).resolves.toBe(true) })
test("Expired", () => {
expect(jwt.verify(expiredToken, secret, { throwError: true })).rejects.toThrowError("EXPIRED")
})
test("Clock offset", () => {
expect(jwt.verify(notYetValidToken, secret, { clockTolerance: offset, throwError: true })).resolves.toBe(true)
expect(jwt.verify(expiredToken, secret, { clockTolerance: offset, throwError: true })).resolves.toBe(true)
expect(jwt.verify(notYetValidToken, secret, { clockTolerance: offset - 1, throwError: true })).rejects.toThrowError("NOT_YET_VALID")
expect(jwt.verify(expiredToken, secret, { clockTolerance: offset - 1, throwError: true })).rejects.toThrowError("EXPIRED")
}) })
}) })

View File

@@ -1,81 +1,81 @@
import { describe, expect, test } from 'vitest' import { describe, expect, test } from "vitest"
import { import {
bytesToByteString, bytesToByteString,
byteStringToBytes, byteStringToBytes,
arrayBufferToBase64String, arrayBufferToBase64String,
base64StringToArrayBuffer, base64StringToArrayBuffer,
textToArrayBuffer, textToArrayBuffer,
arrayBufferToText, arrayBufferToText,
arrayBufferToBase64Url, arrayBufferToBase64Url,
base64UrlToArrayBuffer, base64UrlToArrayBuffer,
textToBase64Url, textToBase64Url,
pemToBinary, pemToBinary,
importTextSecret importTextSecret
} from '../src/utils' } from "../src/utils"
describe('Converters', () => { describe("Converters", () => {
const testString = 'cloudflare-worker-jwt' const testString = "cloudflare-worker-jwt"
const testByteArray = [ 99, 108, 111, 117, 100, 102, 108, 97, 114, 101, 45, 119, 111, 114, 107, 101, 114, 45, 106, 119, 116 ] const testByteArray = [ 99, 108, 111, 117, 100, 102, 108, 97, 114, 101, 45, 119, 111, 114, 107, 101, 114, 45, 106, 119, 116 ]
const testUint8Array = new Uint8Array(testByteArray) const testUint8Array = new Uint8Array(testByteArray)
const testBase64String = 'Y2xvdWRmbGFyZS13b3JrZXItand0' const testBase64String = "Y2xvdWRmbGFyZS13b3JrZXItand0"
const testArrayBuffer = testUint8Array.buffer const testArrayBuffer = testUint8Array.buffer
test('bytesToByteString', () => { test("bytesToByteString", () => {
expect(bytesToByteString(testUint8Array)).toStrictEqual(testString) expect(bytesToByteString(testUint8Array)).toStrictEqual(testString)
}) })
test('byteStringToBytes', () => { test("byteStringToBytes", () => {
expect(byteStringToBytes(testString)).toStrictEqual(testUint8Array) expect(byteStringToBytes(testString)).toStrictEqual(testUint8Array)
}) })
test('arrayBufferToBase64String', () => { test("arrayBufferToBase64String", () => {
expect(arrayBufferToBase64String(testArrayBuffer)).toStrictEqual(testBase64String) expect(arrayBufferToBase64String(testArrayBuffer)).toStrictEqual(testBase64String)
}) })
test('base64StringToArrayBuffer', () => { test("base64StringToArrayBuffer", () => {
expect(base64StringToArrayBuffer(testBase64String)).toStrictEqual(testArrayBuffer) expect(base64StringToArrayBuffer(testBase64String)).toStrictEqual(testArrayBuffer)
}) })
test('textToArrayBuffer', () => { test("textToArrayBuffer", () => {
expect(textToArrayBuffer(testString)).toStrictEqual(testUint8Array) expect(textToArrayBuffer(testString)).toStrictEqual(testUint8Array)
}) })
test('arrayBufferToText', () => { test("arrayBufferToText", () => {
expect(arrayBufferToText(testArrayBuffer)).toStrictEqual(testString) expect(arrayBufferToText(testArrayBuffer)).toStrictEqual(testString)
}) })
test('arrayBufferToBase64Url', () => { test("arrayBufferToBase64Url", () => {
expect(arrayBufferToBase64Url(testArrayBuffer)).toStrictEqual(testBase64String) expect(arrayBufferToBase64Url(testArrayBuffer)).toStrictEqual(testBase64String)
}) })
test('base64UrlToArrayBuffer', () => { test("base64UrlToArrayBuffer", () => {
expect(base64UrlToArrayBuffer(testBase64String)).toStrictEqual(testArrayBuffer) expect(base64UrlToArrayBuffer(testBase64String)).toStrictEqual(testArrayBuffer)
}) })
test('textToBase64Url', () => { test("textToBase64Url", () => {
expect(textToBase64Url(testString)).toStrictEqual(testBase64String) expect(textToBase64Url(testString)).toStrictEqual(testBase64String)
}) })
test('pemToBinary', () => { test("pemToBinary", () => {
expect(pemToBinary(`-----BEGIN PUBLIC KEY-----\n${testBase64String}\n-----END PUBLIC KEY-----`)).toStrictEqual(testArrayBuffer) expect(pemToBinary(`-----BEGIN PUBLIC KEY-----\n${testBase64String}\n-----END PUBLIC KEY-----`)).toStrictEqual(testArrayBuffer)
}) })
}) })
describe('Imports', () => { describe("Imports", () => {
test('importTextSecret', async () => { test("importTextSecret", async () => {
const testKey = 'cloudflare-worker-jwt' const testKey = "cloudflare-worker-jwt"
const testAlgorithm = { name: 'HMAC', hash: { name: 'SHA-256' } } const testAlgorithm = { name: "HMAC", hash: { name: "SHA-256" } }
const testCryptoKey = { type: 'secret', extractable: true, algorithm: { ...testAlgorithm, length: 168 }, usages: ['verify', 'sign'] } const testCryptoKey = { type: "secret", extractable: true, algorithm: { ...testAlgorithm, length: 168 }, usages: ["verify", "sign"] }
expect(await importTextSecret(testKey, testAlgorithm, ['verify', 'sign'])).toMatchObject(testCryptoKey) expect(await importTextSecret(testKey, testAlgorithm, ["verify", "sign"])).toMatchObject(testCryptoKey)
}) })
//test('importJwk', async () => {}) test.todo("importJwk")
//test('importPublicKey', async () => {}) test.todo("importPublicKey")
//test('importPrivateKey', async () => {}) test.todo("importPrivateKey")
//test('importKey', async () => {}) test.todo("importKey")
}) })
//describe('Payload', () => { describe.todo("Payload", () => {
// test('decodePayload', () => {}) test.todo("decodePayload")
//}) })