unjwt 0.1.1 → 0.2.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +3 -3
- package/dist/index.d.mts +7 -6
- package/dist/index.d.ts +7 -6
- package/dist/index.mjs +64 -40
- package/package.json +4 -1
package/README.md
CHANGED
|
@@ -6,8 +6,8 @@ You may just use [Jose](https://github.com/panva/jose) or one of the other libra
|
|
|
6
6
|
|
|
7
7
|
## Features
|
|
8
8
|
|
|
9
|
-
-
|
|
10
|
-
-
|
|
9
|
+
- 📦 Works in Node, browser and workers
|
|
10
|
+
- 💨 Zero dependencies except [`uncrypto`](https://github.com/unjs/uncrypto) for conditional Web Crypto API support
|
|
11
11
|
|
|
12
12
|
## Installation
|
|
13
13
|
|
|
@@ -27,7 +27,7 @@ yarn add unjwt
|
|
|
27
27
|
## Usage
|
|
28
28
|
|
|
29
29
|
```ts
|
|
30
|
-
import { signJWT, verifyJWT } from 'unjwt'
|
|
30
|
+
import { decodeJWT, signJWT, verifyJWT } from 'unjwt'
|
|
31
31
|
|
|
32
32
|
interface JWTUserClaims {
|
|
33
33
|
email: string
|
package/dist/index.d.mts
CHANGED
|
@@ -44,7 +44,10 @@ interface JWTRegisteredClaims {
|
|
|
44
44
|
iat?: number;
|
|
45
45
|
}
|
|
46
46
|
|
|
47
|
-
declare function
|
|
47
|
+
declare function decodeJWT<T extends Record<string, any> = Record<string, any>>(token: string): (JWTRegisteredClaims & T) | undefined;
|
|
48
|
+
declare function _decodeJWT<T extends Record<string, any> = Record<string, any>>(token: string): JWTRegisteredClaims & T;
|
|
49
|
+
|
|
50
|
+
declare function signJWT<T extends Record<string, any> = Record<string, any>>(options: {
|
|
48
51
|
payload?: T;
|
|
49
52
|
secret: string;
|
|
50
53
|
issuer: string;
|
|
@@ -54,14 +57,13 @@ declare function signJWT<T extends Record<string, any> = Record<string, any>>({
|
|
|
54
57
|
* @default 30
|
|
55
58
|
*/
|
|
56
59
|
expires?: number;
|
|
57
|
-
/** @default { typ: 'JWT', alg: 'HS256' } */
|
|
58
|
-
header?: Record<string, any>;
|
|
59
60
|
/** @default 'HMAC' */
|
|
60
61
|
signatureMethod?: string;
|
|
61
62
|
/** @default 'SHA-256' */
|
|
62
63
|
hashMethod?: string;
|
|
63
64
|
}): Promise<string>;
|
|
64
|
-
|
|
65
|
+
|
|
66
|
+
declare function verifyJWT(options: {
|
|
65
67
|
token: string;
|
|
66
68
|
secret: string;
|
|
67
69
|
issuer: string;
|
|
@@ -73,6 +75,5 @@ declare function verifyJWT({ token, secret, issuer, audience, leeway, signatureM
|
|
|
73
75
|
/** @default 'SHA-256' */
|
|
74
76
|
hashMethod?: string;
|
|
75
77
|
}): Promise<void>;
|
|
76
|
-
declare function decodeJWT<T extends Record<string, any> = Record<string, any>>(token: string): JWTRegisteredClaims & T;
|
|
77
78
|
|
|
78
|
-
export { JWTRegisteredClaims, decodeJWT, signJWT, verifyJWT };
|
|
79
|
+
export { JWTRegisteredClaims, _decodeJWT, decodeJWT, signJWT, verifyJWT };
|
package/dist/index.d.ts
CHANGED
|
@@ -44,7 +44,10 @@ interface JWTRegisteredClaims {
|
|
|
44
44
|
iat?: number;
|
|
45
45
|
}
|
|
46
46
|
|
|
47
|
-
declare function
|
|
47
|
+
declare function decodeJWT<T extends Record<string, any> = Record<string, any>>(token: string): (JWTRegisteredClaims & T) | undefined;
|
|
48
|
+
declare function _decodeJWT<T extends Record<string, any> = Record<string, any>>(token: string): JWTRegisteredClaims & T;
|
|
49
|
+
|
|
50
|
+
declare function signJWT<T extends Record<string, any> = Record<string, any>>(options: {
|
|
48
51
|
payload?: T;
|
|
49
52
|
secret: string;
|
|
50
53
|
issuer: string;
|
|
@@ -54,14 +57,13 @@ declare function signJWT<T extends Record<string, any> = Record<string, any>>({
|
|
|
54
57
|
* @default 30
|
|
55
58
|
*/
|
|
56
59
|
expires?: number;
|
|
57
|
-
/** @default { typ: 'JWT', alg: 'HS256' } */
|
|
58
|
-
header?: Record<string, any>;
|
|
59
60
|
/** @default 'HMAC' */
|
|
60
61
|
signatureMethod?: string;
|
|
61
62
|
/** @default 'SHA-256' */
|
|
62
63
|
hashMethod?: string;
|
|
63
64
|
}): Promise<string>;
|
|
64
|
-
|
|
65
|
+
|
|
66
|
+
declare function verifyJWT(options: {
|
|
65
67
|
token: string;
|
|
66
68
|
secret: string;
|
|
67
69
|
issuer: string;
|
|
@@ -73,6 +75,5 @@ declare function verifyJWT({ token, secret, issuer, audience, leeway, signatureM
|
|
|
73
75
|
/** @default 'SHA-256' */
|
|
74
76
|
hashMethod?: string;
|
|
75
77
|
}): Promise<void>;
|
|
76
|
-
declare function decodeJWT<T extends Record<string, any> = Record<string, any>>(token: string): JWTRegisteredClaims & T;
|
|
77
78
|
|
|
78
|
-
export { JWTRegisteredClaims, decodeJWT, signJWT, verifyJWT };
|
|
79
|
+
export { JWTRegisteredClaims, _decodeJWT, decodeJWT, signJWT, verifyJWT };
|
package/dist/index.mjs
CHANGED
|
@@ -1,19 +1,22 @@
|
|
|
1
|
+
import { subtle } from 'uncrypto';
|
|
2
|
+
|
|
1
3
|
const DEFAULT_SIGNATURE_METHOD = "HMAC";
|
|
2
4
|
const DEFAULT_HASH_METHODS = "SHA-256";
|
|
3
5
|
const textEncoder = new TextEncoder();
|
|
4
6
|
async function createSignature(key, algorithm, data) {
|
|
5
7
|
const encoded = textEncoder.encode(data);
|
|
6
|
-
const signature = await
|
|
8
|
+
const signature = await subtle.sign(algorithm, key, encoded);
|
|
7
9
|
return encodeToBase64Url(signature);
|
|
8
10
|
}
|
|
9
|
-
async function importKey({
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
11
|
+
async function importKey(options) {
|
|
12
|
+
const {
|
|
13
|
+
secret,
|
|
14
|
+
usage = "sign",
|
|
15
|
+
name = DEFAULT_SIGNATURE_METHOD,
|
|
16
|
+
hash = DEFAULT_HASH_METHODS
|
|
17
|
+
} = { ...options };
|
|
15
18
|
const encodedKey = textEncoder.encode(secret);
|
|
16
|
-
return await
|
|
19
|
+
return await subtle.importKey(
|
|
17
20
|
"raw",
|
|
18
21
|
encodedKey,
|
|
19
22
|
{ name, hash },
|
|
@@ -42,21 +45,44 @@ function decodeFromBase64UrlToBuffer(base64Url) {
|
|
|
42
45
|
return buffer.buffer;
|
|
43
46
|
}
|
|
44
47
|
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
48
|
+
function decodeJWT(token) {
|
|
49
|
+
try {
|
|
50
|
+
return _decodeJWT(token);
|
|
51
|
+
} catch {
|
|
52
|
+
}
|
|
53
|
+
}
|
|
54
|
+
function _decodeJWT(token) {
|
|
55
|
+
const parts = String(token).split(".");
|
|
56
|
+
if (parts.length !== 3)
|
|
57
|
+
throw new Error("Invalid token format");
|
|
58
|
+
const [, payload] = parts;
|
|
59
|
+
return JSON.parse(decodeFromBase64Url(payload));
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
const headerAlgMap = {
|
|
63
|
+
HMAC: "HS",
|
|
64
|
+
RSA: "RS",
|
|
65
|
+
ECDSA: "ES"
|
|
66
|
+
};
|
|
67
|
+
async function signJWT(options) {
|
|
68
|
+
const {
|
|
69
|
+
payload = {},
|
|
70
|
+
secret,
|
|
71
|
+
issuer,
|
|
72
|
+
audience,
|
|
73
|
+
expires = 30,
|
|
74
|
+
signatureMethod = DEFAULT_SIGNATURE_METHOD,
|
|
75
|
+
hashMethod = DEFAULT_HASH_METHODS
|
|
76
|
+
} = { ...options };
|
|
55
77
|
const key = await importKey({
|
|
56
78
|
secret,
|
|
57
79
|
name: signatureMethod,
|
|
58
80
|
hash: hashMethod
|
|
59
81
|
});
|
|
82
|
+
const header = {
|
|
83
|
+
typ: "JWT",
|
|
84
|
+
alg: `${headerAlgMap[signatureMethod]}${hashMethod.split("-")[1]}`
|
|
85
|
+
};
|
|
60
86
|
const iat = Math.floor(Date.now() / 1e3);
|
|
61
87
|
const exp = iat + expires * 24 * 60 * 60;
|
|
62
88
|
const jwtPayload = {
|
|
@@ -75,23 +101,25 @@ async function signJWT({
|
|
|
75
101
|
jwtPayload
|
|
76
102
|
)}.${signature}`;
|
|
77
103
|
}
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
104
|
+
|
|
105
|
+
async function verifyJWT(options) {
|
|
106
|
+
const {
|
|
107
|
+
token,
|
|
108
|
+
secret,
|
|
109
|
+
issuer,
|
|
110
|
+
audience,
|
|
111
|
+
leeway = 60,
|
|
112
|
+
signatureMethod = DEFAULT_SIGNATURE_METHOD,
|
|
113
|
+
hashMethod = DEFAULT_HASH_METHODS
|
|
114
|
+
} = { ...options };
|
|
115
|
+
const [header, payload, signature] = String(token).split(".");
|
|
88
116
|
const key = await importKey({
|
|
89
117
|
secret,
|
|
90
118
|
usage: "verify",
|
|
91
119
|
name: signatureMethod,
|
|
92
120
|
hash: hashMethod
|
|
93
121
|
});
|
|
94
|
-
const isValid = await
|
|
122
|
+
const isValid = await subtle.verify(
|
|
95
123
|
signatureMethod,
|
|
96
124
|
key,
|
|
97
125
|
decodeFromBase64UrlToBuffer(signature),
|
|
@@ -99,19 +127,15 @@ async function verifyJWT({
|
|
|
99
127
|
);
|
|
100
128
|
if (!isValid)
|
|
101
129
|
throw new Error("Invalid JWT signature");
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
130
|
+
let decodedPayload;
|
|
131
|
+
try {
|
|
132
|
+
decodedPayload = JSON.parse(decodeFromBase64Url(payload));
|
|
133
|
+
} catch {
|
|
134
|
+
throw new Error("Invalid JWT payload");
|
|
135
|
+
}
|
|
105
136
|
const now = Math.floor(Date.now() / 1e3);
|
|
106
137
|
if (issuer !== decodedPayload.iss || (Array.isArray(decodedPayload.aud) ? !decodedPayload.aud.includes(audience) : audience !== decodedPayload.aud) || decodedPayload.exp && now > decodedPayload.exp + leeway || decodedPayload.nbf && now < decodedPayload.nbf - leeway)
|
|
107
138
|
throw new Error("Invalid JWT claims");
|
|
108
139
|
}
|
|
109
|
-
function decodeJWT(token) {
|
|
110
|
-
const parts = token.split(".");
|
|
111
|
-
if (parts.length !== 3)
|
|
112
|
-
throw new Error("Invalid token format");
|
|
113
|
-
const [, payload] = parts;
|
|
114
|
-
return JSON.parse(decodeFromBase64Url(payload));
|
|
115
|
-
}
|
|
116
140
|
|
|
117
|
-
export { decodeJWT, signJWT, verifyJWT };
|
|
141
|
+
export { _decodeJWT, decodeJWT, signJWT, verifyJWT };
|
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "unjwt",
|
|
3
3
|
"type": "module",
|
|
4
|
-
"version": "0.
|
|
4
|
+
"version": "0.2.0",
|
|
5
5
|
"packageManager": "pnpm@8.6.12",
|
|
6
6
|
"description": "Easy creation and verification of JSON Web Tokens (JWT)",
|
|
7
7
|
"author": "Johann Schopplich <pkg@johannschopplich.com>",
|
|
@@ -40,6 +40,9 @@
|
|
|
40
40
|
"release": "bumpp --commit --push --tag",
|
|
41
41
|
"test:types": "tsc --noEmit"
|
|
42
42
|
},
|
|
43
|
+
"dependencies": {
|
|
44
|
+
"uncrypto": "^0.1.3"
|
|
45
|
+
},
|
|
43
46
|
"devDependencies": {
|
|
44
47
|
"@antfu/eslint-config": "^0.40.2",
|
|
45
48
|
"bumpp": "^9.1.1",
|