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 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
- - 💨 Zero dependencies
10
- - 📦 Works in every context supporting the Web Crypto API
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 signJWT<T extends Record<string, any> = Record<string, any>>({ payload, secret, issuer, audience, expires, header, signatureMethod, hashMethod, }: {
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
- declare function verifyJWT({ token, secret, issuer, audience, leeway, signatureMethod, hashMethod, }: {
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 signJWT<T extends Record<string, any> = Record<string, any>>({ payload, secret, issuer, audience, expires, header, signatureMethod, hashMethod, }: {
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
- declare function verifyJWT({ token, secret, issuer, audience, leeway, signatureMethod, hashMethod, }: {
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 crypto.subtle.sign(algorithm, key, encoded);
8
+ const signature = await subtle.sign(algorithm, key, encoded);
7
9
  return encodeToBase64Url(signature);
8
10
  }
9
- async function importKey({
10
- secret,
11
- usage = "sign",
12
- name = DEFAULT_SIGNATURE_METHOD,
13
- hash = DEFAULT_HASH_METHODS
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 crypto.subtle.importKey(
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
- async function signJWT({
46
- payload = {},
47
- secret,
48
- issuer,
49
- audience,
50
- expires = 30,
51
- header = { typ: "JWT", alg: "HS256" },
52
- signatureMethod = DEFAULT_SIGNATURE_METHOD,
53
- hashMethod = DEFAULT_HASH_METHODS
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
- async function verifyJWT({
79
- token,
80
- secret,
81
- issuer,
82
- audience,
83
- leeway = 60,
84
- signatureMethod = DEFAULT_SIGNATURE_METHOD,
85
- hashMethod = DEFAULT_HASH_METHODS
86
- }) {
87
- const [header, payload, signature] = token.split(".");
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 crypto.subtle.verify(
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
- const decodedPayload = JSON.parse(
103
- decodeFromBase64Url(payload)
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.1.1",
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",