1
0

Compare commits

..

13 Commits

Author SHA1 Message Date
21ec1b6f2a Update to v1.4.3 2022-06-22 12:37:08 +02:00
Toby Schneider
97df6e7f81 Merge pull request #17 from IMZihad21/main
Destructure payload from decode function properly
2022-06-22 12:11:09 +02:00
ZèD
7198501a40 Destructure payload from decode function properly
The decode function returns an object containing a header and payload properties. Assigning the whole object to payload fails nbf and exp checks on verify JWT as those properties not found in decode return object directly. Instead, destructure payload property from decode return data that contains those values and check them correctly.

Signed-off-by: ZèD <imzihad@gmail.com>
2022-06-22 12:06:50 +06:00
cb6209b1b6 Docs fix 2022-06-04 22:29:46 +02:00
8f4e5e3199 Docs fix 2022-06-04 22:29:30 +02:00
594cdd6c05 Docs fix 2022-06-04 17:43:48 +02:00
f85abf30a8 Update docs 2022-06-04 17:43:11 +02:00
095b1d43f3 Update docs 2022-06-04 17:42:33 +02:00
0bc128fec1 Update docs 2022-06-04 17:40:47 +02:00
f846695242 Update docs 2022-06-04 17:29:50 +02:00
695e1c0dfe .decode() syntax change to support headers 2022-06-04 17:23:53 +02:00
64da4c625f .verify() bugfix 2022-06-04 14:53:59 +02:00
e4038ae0a7 Just to make sure 2022-06-04 14:40:06 +02:00
6 changed files with 63 additions and 26 deletions

View File

@@ -8,6 +8,9 @@ A lightweight JWT implementation with ZERO dependencies for Cloudflare Workers.
- [Install](#install)
- [Examples](#examples)
- [Usage](#usage)
- [Sign](#sign)
- [Verify](#verify)
- [Decode](#decode)
## Install
@@ -36,7 +39,7 @@ async () => {
return
// Decoding token
const payload = jwt.decode(token)
const { payload } = jwt.decode(token)
}
```
@@ -62,15 +65,20 @@ async () => {
return
// Decoding token
const payload = jwt.decode(token) // { name: 'John Doe', email: 'john.doe@gmail.com', ... }
const { payload } = jwt.decode(token) // { name: 'John Doe', email: 'john.doe@gmail.com', ... }
}
```
## Usage
- [Sign](#sign)
- [Verify](#verify)
- [Decode](#decode)
<hr>
### `jwt.sign(payload, secret, [options])`
### Sign
#### `jwt.sign(payload, secret, [options])`
Signs a payload and returns the token.
@@ -80,14 +88,15 @@ Argument | Type | Satus | 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.
`secret` | `string` | required | - | A string which is used to sign the payload.
`options` | `object`, `string` | optional | `{ algorithm: 'HS256' }` | The options object supporting `algorithm` and `keyid` or just the algorithm string. (See [Available Algorithms](#available-algorithms))
`options` | `object` | optional | `{ algorithm: 'HS256' }` | The options object supporting `algorithm` and `keyid`. (See [Available Algorithms](#available-algorithms))
#### `return`
Returns token as a `string`.
<hr>
### `jwt.verify(token, secret, [options])`
### Verify
#### `jwt.verify(token, secret, [options])`
Verifies the integrity of the token and returns a boolean value.
@@ -95,14 +104,18 @@ Argument | Type | Satus | Default | Description
----------- | -------- | -------- | ------- | -----------
`token` | `string` | required | - | The token string generated by `jwt.sign()`.
`secret` | `string` | required | - | The string which was used to sign the payload.
`algorithm` | `object`, `string` | optional | `{ algorithm: 'HS256', throwError: false }` | The options object supporting `algorithm` or just the algorithm string. (See [Available Algorithms](#available-algorithms))
`options` | `object` | optional | `{ algorithm: 'HS256', throwError: false }` | The options object supporting `algorithm` and `throwError`. (See [Available Algorithms](#available-algorithms))
#### `throws`
If `options.throwError` is `true` and the token is invalid, an error will be thrown.
#### `return`
Returns `true` if signature, `nbf` (if set) and `exp` (if set) are valid, otherwise returns `false`.
<hr>
### `jwt.decode(token)`
### Decode
#### `jwt.decode(token)`
Returns the payload **without** verifying the integrity of the token. Please use `jwt.verify()` first to keep your application secure!
@@ -111,7 +124,19 @@ Argument | Type | Satus | Default | Description
`token` | `string` | required | - | The token string generated by `jwt.sign()`.
#### `return`
Returns payload `object`.
Returns an `object` containing `header` and `payload`:
```javascript
{
header: {
alg: 'HS256',
typ: 'JWT'
},
payload: {
name: 'John Doe',
email: 'john.doe@gmail.com'
}
}
```
### Available Algorithms
- ES256

9
index.d.ts vendored
View File

@@ -33,9 +33,9 @@ declare class JWT {
* Returns the payload **without** verifying the integrity of the token. Please use `jwt.verify()` first to keep your application secure!
*
* @param {string} token The token string generated by `jwt.sign()`.
* @returns {object | null} Returns payload `object`.
* @returns {JWTDecodeReturn} Returns an `object` containing `header` and `payload`.
*/
decode(token: string): object | null
decode(token: string): JWTDecodeReturn
}
declare const _exports: JWT
@@ -52,4 +52,9 @@ type JWTVerifyOptions = {
throwError?: boolean
}
type JWTDecodeReturn = {
header: object,
payload: object
}
export = _exports

View File

@@ -94,7 +94,7 @@ class JWT {
const importAlgorithm = this.algorithms[options.algorithm]
if (!importAlgorithm)
throw new Error('algorithm not found')
const payload = this.decode(token)
const { payload } = this.decode(token)
if (payload.nbf && payload.nbf > Math.floor(Date.now() / 1000)) {
if (options.throwError)
throw 'NOT_YET_VALID'
@@ -113,10 +113,13 @@ class JWT {
} else
keyData = this._utf8ToUint8Array(secret)
const key = await crypto.subtle.importKey(keyFormat, keyData, importAlgorithm, false, ['verify'])
return await crypto.subtle.verify(importAlgorithm, key, Base64URL.parse(tokenParts[2]), `${tokenParts[0]}.${tokenParts[1]}`)
return await crypto.subtle.verify(importAlgorithm, key, Base64URL.parse(tokenParts[2]), this._utf8ToUint8Array(`${tokenParts[0]}.${tokenParts[1]}`))
}
decode(token) {
return this._decodePayload(token.split('.')[1].replace(/-/g, '+').replace(/_/g, '/'))
return {
header: this._decodePayload(token.split('.')[0].replace(/-/g, '+').replace(/_/g, '/')),
payload: this._decodePayload(token.split('.')[1].replace(/-/g, '+').replace(/_/g, '/'))
}
}
}

View File

@@ -1,4 +1,4 @@
const { subtle } = require('crypto').webcrypto
const { subtle } = require('node:crypto').webcrypto
Object.defineProperty(global, 'crypto', {
value: { subtle }
})
@@ -115,12 +115,14 @@ test.each(Object.entries(secrets))(`Self test: %s`, async (algorithm, key) => {
privateKey = key.private
publicKey = key.public
}
const token = await JWT.sign(testPayload, privateKey, { algorithm })
expect(token).toMatch(/^[a-zA-Z0-9\-_]+\.[a-zA-Z0-9\-_]+\.[a-zA-Z0-9\-_]+$/)
const verified = await JWT.verify(token, publicKey, { algorithm })
expect(verified).toBeTruthy()
const payload = JWT.decode(token)
expect(payload).toBeTruthy()
const { payload } = JWT.decode(token)
expect({
sub: payload.sub,
name: payload.name
@@ -151,9 +153,11 @@ test.each(Object.entries(externalTokens))('Verify external tokens: %s', async (a
privateKey = key.private
publicKey = key.public
}
const verified = await JWT.verify(token, publicKey, { algorithm })
expect(verified).toBeTruthy()
const payload = JWT.decode(token)
const { payload } = JWT.decode(token)
expect({
sub: payload.sub,
name: payload.name

16
package-lock.json generated
View File

@@ -1,12 +1,12 @@
{
"name": "@tsndr/cloudflare-worker-jwt",
"version": "1.2.0",
"version": "1.4.3",
"lockfileVersion": 2,
"requires": true,
"packages": {
"": {
"name": "@tsndr/cloudflare-worker-jwt",
"version": "1.2.0",
"version": "1.4.3",
"license": "MIT",
"devDependencies": {
"jest": "^28.1.0"
@@ -4262,9 +4262,9 @@
}
},
"node_modules/path-parse": {
"version": "1.0.6",
"resolved": "https://registry.npmjs.org/path-parse/-/path-parse-1.0.6.tgz",
"integrity": "sha512-GSmOT2EbHrINBf9SR7CDELwlJ8AENk3Qn7OikK4nFYAu3Ote2+JYNVvkpAEQm3/TLNEJFD/xZJjzyxg3KBWOzw==",
"version": "1.0.7",
"resolved": "https://registry.npmjs.org/path-parse/-/path-parse-1.0.7.tgz",
"integrity": "sha512-LDJzPVEEEPR+y48z93A0Ed0yXb8pAByGWo/k5YYdYgpY2/2EsOsksJrq7lOHxryrVOn1ejG6oAp8ahvOIQD8sw==",
"dev": true
},
"node_modules/picocolors": {
@@ -8066,9 +8066,9 @@
"dev": true
},
"path-parse": {
"version": "1.0.6",
"resolved": "https://registry.npmjs.org/path-parse/-/path-parse-1.0.6.tgz",
"integrity": "sha512-GSmOT2EbHrINBf9SR7CDELwlJ8AENk3Qn7OikK4nFYAu3Ote2+JYNVvkpAEQm3/TLNEJFD/xZJjzyxg3KBWOzw==",
"version": "1.0.7",
"resolved": "https://registry.npmjs.org/path-parse/-/path-parse-1.0.7.tgz",
"integrity": "sha512-LDJzPVEEEPR+y48z93A0Ed0yXb8pAByGWo/k5YYdYgpY2/2EsOsksJrq7lOHxryrVOn1ejG6oAp8ahvOIQD8sw==",
"dev": true
},
"picocolors": {

View File

@@ -1,6 +1,6 @@
{
"name": "@tsndr/cloudflare-worker-jwt",
"version": "1.3.0",
"version": "1.4.3",
"description": "A lightweight JWT implementation with ZERO dependencies for Cloudflare Worker",
"main": "index.js",
"scripts": {