hono 4.11.2 → 4.11.4
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/dist/cjs/middleware/jwk/jwk.js +5 -1
- package/dist/cjs/middleware/jwt/jwt.js +3 -0
- package/dist/cjs/utils/jwt/jwt.js +26 -3
- package/dist/cjs/utils/jwt/types.js +32 -0
- package/dist/middleware/jwk/jwk.js +5 -1
- package/dist/middleware/jwt/jwt.js +3 -0
- package/dist/types/adapter/bun/websocket.d.ts +1 -1
- package/dist/types/middleware/jwk/jwk.d.ts +3 -0
- package/dist/types/middleware/jwt/jwt.d.ts +5 -3
- package/dist/types/types.d.ts +2 -1
- package/dist/types/utils/jwt/index.d.ts +2 -1
- package/dist/types/utils/jwt/jwa.d.ts +2 -0
- package/dist/types/utils/jwt/jwt.d.ts +4 -3
- package/dist/types/utils/jwt/types.d.ts +12 -0
- package/dist/utils/jwt/jwt.js +30 -3
- package/dist/utils/jwt/types.js +28 -0
- package/package.json +2 -2
|
@@ -93,7 +93,11 @@ const jwk = (options, init) => {
|
|
|
93
93
|
try {
|
|
94
94
|
const keys = typeof options.keys === "function" ? await options.keys(ctx) : options.keys;
|
|
95
95
|
const jwks_uri = typeof options.jwks_uri === "function" ? await options.jwks_uri(ctx) : options.jwks_uri;
|
|
96
|
-
payload = await import_jwt.Jwt.verifyWithJwks(
|
|
96
|
+
payload = await import_jwt.Jwt.verifyWithJwks(
|
|
97
|
+
token,
|
|
98
|
+
{ keys, jwks_uri, verification: verifyOpts, allowedAlgorithms: options.alg },
|
|
99
|
+
init
|
|
100
|
+
);
|
|
97
101
|
} catch (e) {
|
|
98
102
|
cause = e;
|
|
99
103
|
}
|
|
@@ -34,6 +34,9 @@ const jwt = (options) => {
|
|
|
34
34
|
if (!options || !options.secret) {
|
|
35
35
|
throw new Error('JWT auth middleware requires options for "secret"');
|
|
36
36
|
}
|
|
37
|
+
if (!options.alg) {
|
|
38
|
+
throw new Error('JWT auth middleware requires options for "alg"');
|
|
39
|
+
}
|
|
37
40
|
if (!crypto.subtle || !crypto.subtle.importKey) {
|
|
38
41
|
throw new Error("`crypto.subtle.importKey` is undefined. JWT auth middleware requires it.");
|
|
39
42
|
}
|
|
@@ -56,14 +56,20 @@ const sign = async (payload, privateKey, alg = "HS256") => {
|
|
|
56
56
|
return `${partialToken}.${signature}`;
|
|
57
57
|
};
|
|
58
58
|
const verify = async (token, publicKey, algOrOptions) => {
|
|
59
|
+
if (!algOrOptions) {
|
|
60
|
+
throw new import_types.JwtAlgorithmRequired();
|
|
61
|
+
}
|
|
59
62
|
const {
|
|
60
|
-
alg
|
|
63
|
+
alg,
|
|
61
64
|
iss,
|
|
62
65
|
nbf = true,
|
|
63
66
|
exp = true,
|
|
64
67
|
iat = true,
|
|
65
68
|
aud
|
|
66
|
-
} = typeof algOrOptions === "string" ? { alg: algOrOptions } : algOrOptions
|
|
69
|
+
} = typeof algOrOptions === "string" ? { alg: algOrOptions } : algOrOptions;
|
|
70
|
+
if (!alg) {
|
|
71
|
+
throw new import_types.JwtAlgorithmRequired();
|
|
72
|
+
}
|
|
67
73
|
const tokenParts = token.split(".");
|
|
68
74
|
if (tokenParts.length !== 3) {
|
|
69
75
|
throw new import_types.JwtTokenInvalid(token);
|
|
@@ -72,6 +78,9 @@ const verify = async (token, publicKey, algOrOptions) => {
|
|
|
72
78
|
if (!isTokenHeader(header)) {
|
|
73
79
|
throw new import_types.JwtHeaderInvalid(header);
|
|
74
80
|
}
|
|
81
|
+
if (header.alg !== alg) {
|
|
82
|
+
throw new import_types.JwtAlgorithmMismatch(alg, header.alg);
|
|
83
|
+
}
|
|
75
84
|
const now = Date.now() / 1e3 | 0;
|
|
76
85
|
if (nbf && payload.nbf && payload.nbf > now) {
|
|
77
86
|
throw new import_types.JwtTokenNotBefore(token);
|
|
@@ -117,6 +126,11 @@ const verify = async (token, publicKey, algOrOptions) => {
|
|
|
117
126
|
}
|
|
118
127
|
return payload;
|
|
119
128
|
};
|
|
129
|
+
const symmetricAlgorithms = [
|
|
130
|
+
import_jwa.AlgorithmTypes.HS256,
|
|
131
|
+
import_jwa.AlgorithmTypes.HS384,
|
|
132
|
+
import_jwa.AlgorithmTypes.HS512
|
|
133
|
+
];
|
|
120
134
|
const verifyWithJwks = async (token, options, init) => {
|
|
121
135
|
const verifyOpts = options.verification || {};
|
|
122
136
|
const header = decodeHeader(token);
|
|
@@ -126,6 +140,12 @@ const verifyWithJwks = async (token, options, init) => {
|
|
|
126
140
|
if (!header.kid) {
|
|
127
141
|
throw new import_types.JwtHeaderRequiresKid(header);
|
|
128
142
|
}
|
|
143
|
+
if (symmetricAlgorithms.includes(header.alg)) {
|
|
144
|
+
throw new import_types.JwtSymmetricAlgorithmNotAllowed(header.alg);
|
|
145
|
+
}
|
|
146
|
+
if (!options.allowedAlgorithms.includes(header.alg)) {
|
|
147
|
+
throw new import_types.JwtAlgorithmNotAllowed(header.alg, options.allowedAlgorithms);
|
|
148
|
+
}
|
|
129
149
|
if (options.jwks_uri) {
|
|
130
150
|
const response = await fetch(options.jwks_uri, init);
|
|
131
151
|
if (!response.ok) {
|
|
@@ -150,8 +170,11 @@ const verifyWithJwks = async (token, options, init) => {
|
|
|
150
170
|
if (!matchingKey) {
|
|
151
171
|
throw new import_types.JwtTokenInvalid(token);
|
|
152
172
|
}
|
|
173
|
+
if (matchingKey.alg && matchingKey.alg !== header.alg) {
|
|
174
|
+
throw new import_types.JwtAlgorithmMismatch(matchingKey.alg, header.alg);
|
|
175
|
+
}
|
|
153
176
|
return await verify(token, matchingKey, {
|
|
154
|
-
alg:
|
|
177
|
+
alg: header.alg,
|
|
155
178
|
...verifyOpts
|
|
156
179
|
});
|
|
157
180
|
};
|
|
@@ -19,10 +19,14 @@ var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: tru
|
|
|
19
19
|
var types_exports = {};
|
|
20
20
|
__export(types_exports, {
|
|
21
21
|
CryptoKeyUsage: () => CryptoKeyUsage,
|
|
22
|
+
JwtAlgorithmMismatch: () => JwtAlgorithmMismatch,
|
|
23
|
+
JwtAlgorithmNotAllowed: () => JwtAlgorithmNotAllowed,
|
|
22
24
|
JwtAlgorithmNotImplemented: () => JwtAlgorithmNotImplemented,
|
|
25
|
+
JwtAlgorithmRequired: () => JwtAlgorithmRequired,
|
|
23
26
|
JwtHeaderInvalid: () => JwtHeaderInvalid,
|
|
24
27
|
JwtHeaderRequiresKid: () => JwtHeaderRequiresKid,
|
|
25
28
|
JwtPayloadRequiresAud: () => JwtPayloadRequiresAud,
|
|
29
|
+
JwtSymmetricAlgorithmNotAllowed: () => JwtSymmetricAlgorithmNotAllowed,
|
|
26
30
|
JwtTokenAudience: () => JwtTokenAudience,
|
|
27
31
|
JwtTokenExpired: () => JwtTokenExpired,
|
|
28
32
|
JwtTokenInvalid: () => JwtTokenInvalid,
|
|
@@ -38,6 +42,18 @@ class JwtAlgorithmNotImplemented extends Error {
|
|
|
38
42
|
this.name = "JwtAlgorithmNotImplemented";
|
|
39
43
|
}
|
|
40
44
|
}
|
|
45
|
+
class JwtAlgorithmRequired extends Error {
|
|
46
|
+
constructor() {
|
|
47
|
+
super('JWT verification requires "alg" option to be specified');
|
|
48
|
+
this.name = "JwtAlgorithmRequired";
|
|
49
|
+
}
|
|
50
|
+
}
|
|
51
|
+
class JwtAlgorithmMismatch extends Error {
|
|
52
|
+
constructor(expected, actual) {
|
|
53
|
+
super(`JWT algorithm mismatch: expected "${expected}", got "${actual}"`);
|
|
54
|
+
this.name = "JwtAlgorithmMismatch";
|
|
55
|
+
}
|
|
56
|
+
}
|
|
41
57
|
class JwtTokenInvalid extends Error {
|
|
42
58
|
constructor(token) {
|
|
43
59
|
super(`invalid JWT token: ${token}`);
|
|
@@ -82,6 +98,18 @@ class JwtHeaderRequiresKid extends Error {
|
|
|
82
98
|
this.name = "JwtHeaderRequiresKid";
|
|
83
99
|
}
|
|
84
100
|
}
|
|
101
|
+
class JwtSymmetricAlgorithmNotAllowed extends Error {
|
|
102
|
+
constructor(alg) {
|
|
103
|
+
super(`symmetric algorithm "${alg}" is not allowed for JWK verification`);
|
|
104
|
+
this.name = "JwtSymmetricAlgorithmNotAllowed";
|
|
105
|
+
}
|
|
106
|
+
}
|
|
107
|
+
class JwtAlgorithmNotAllowed extends Error {
|
|
108
|
+
constructor(alg, allowedAlgorithms) {
|
|
109
|
+
super(`algorithm "${alg}" is not in the allowed list: [${allowedAlgorithms.join(", ")}]`);
|
|
110
|
+
this.name = "JwtAlgorithmNotAllowed";
|
|
111
|
+
}
|
|
112
|
+
}
|
|
85
113
|
class JwtTokenSignatureMismatched extends Error {
|
|
86
114
|
constructor(token) {
|
|
87
115
|
super(`token(${token}) signature mismatched`);
|
|
@@ -116,10 +144,14 @@ var CryptoKeyUsage = /* @__PURE__ */ ((CryptoKeyUsage2) => {
|
|
|
116
144
|
// Annotate the CommonJS export names for ESM import in node:
|
|
117
145
|
0 && (module.exports = {
|
|
118
146
|
CryptoKeyUsage,
|
|
147
|
+
JwtAlgorithmMismatch,
|
|
148
|
+
JwtAlgorithmNotAllowed,
|
|
119
149
|
JwtAlgorithmNotImplemented,
|
|
150
|
+
JwtAlgorithmRequired,
|
|
120
151
|
JwtHeaderInvalid,
|
|
121
152
|
JwtHeaderRequiresKid,
|
|
122
153
|
JwtPayloadRequiresAud,
|
|
154
|
+
JwtSymmetricAlgorithmNotAllowed,
|
|
123
155
|
JwtTokenAudience,
|
|
124
156
|
JwtTokenExpired,
|
|
125
157
|
JwtTokenInvalid,
|
|
@@ -71,7 +71,11 @@ var jwk = (options, init) => {
|
|
|
71
71
|
try {
|
|
72
72
|
const keys = typeof options.keys === "function" ? await options.keys(ctx) : options.keys;
|
|
73
73
|
const jwks_uri = typeof options.jwks_uri === "function" ? await options.jwks_uri(ctx) : options.jwks_uri;
|
|
74
|
-
payload = await Jwt.verifyWithJwks(
|
|
74
|
+
payload = await Jwt.verifyWithJwks(
|
|
75
|
+
token,
|
|
76
|
+
{ keys, jwks_uri, verification: verifyOpts, allowedAlgorithms: options.alg },
|
|
77
|
+
init
|
|
78
|
+
);
|
|
75
79
|
} catch (e) {
|
|
76
80
|
cause = e;
|
|
77
81
|
}
|
|
@@ -8,6 +8,9 @@ var jwt = (options) => {
|
|
|
8
8
|
if (!options || !options.secret) {
|
|
9
9
|
throw new Error('JWT auth middleware requires options for "secret"');
|
|
10
10
|
}
|
|
11
|
+
if (!options.alg) {
|
|
12
|
+
throw new Error('JWT auth middleware requires options for "alg"');
|
|
13
|
+
}
|
|
11
14
|
if (!crypto.subtle || !crypto.subtle.importKey) {
|
|
12
15
|
throw new Error("`crypto.subtle.importKey` is undefined. JWT auth middleware requires it.");
|
|
13
16
|
}
|
|
@@ -32,7 +32,7 @@ export declare const createWSContext: (ws: BunServerWebSocket<BunWebSocketData>)
|
|
|
32
32
|
export declare const upgradeWebSocket: UpgradeWebSocket<any>;
|
|
33
33
|
export declare const websocket: BunWebSocketHandler<BunWebSocketData>;
|
|
34
34
|
/**
|
|
35
|
-
* @deprecated Import `
|
|
35
|
+
* @deprecated Import `upgradeWebSocket` and `websocket` directly from `hono/bun` instead.
|
|
36
36
|
* @returns A function to create a Bun WebSocket handler.
|
|
37
37
|
*/
|
|
38
38
|
export declare const createBunWebSocket: <T>() => CreateWebSocket<T>;
|
|
@@ -6,6 +6,7 @@ import type { Context } from '../../context';
|
|
|
6
6
|
import type { MiddlewareHandler } from '../../types';
|
|
7
7
|
import type { CookiePrefixOptions } from '../../utils/cookie';
|
|
8
8
|
import '../../context';
|
|
9
|
+
import type { AsymmetricAlgorithm } from '../../utils/jwt/jwa';
|
|
9
10
|
import type { HonoJsonWebKey } from '../../utils/jwt/jws';
|
|
10
11
|
import type { VerifyOptions } from '../../utils/jwt/jwt';
|
|
11
12
|
/**
|
|
@@ -19,6 +20,7 @@ import type { VerifyOptions } from '../../utils/jwt/jwt';
|
|
|
19
20
|
* @param {boolean} [options.allow_anon] - If set to `true`, the middleware allows requests without a token to proceed without authentication.
|
|
20
21
|
* @param {string} [options.cookie] - If set, the middleware attempts to retrieve the token from a cookie with these options (optionally signed) only if no token is found in the header.
|
|
21
22
|
* @param {string} [options.headerName='Authorization'] - The name of the header to look for the JWT token. Default is 'Authorization'.
|
|
23
|
+
* @param {AsymmetricAlgorithm[]} options.alg - An array of allowed asymmetric algorithms for JWT verification. Only tokens signed with these algorithms will be accepted.
|
|
22
24
|
* @param {RequestInit} [init] - Optional init options for the `fetch` request when retrieving JWKS from a URI.
|
|
23
25
|
* @param {VerifyOptions} [options.verification] - Additional options for JWK payload verification.
|
|
24
26
|
* @returns {MiddlewareHandler} The middleware handler function.
|
|
@@ -47,5 +49,6 @@ export declare const jwk: (options: {
|
|
|
47
49
|
prefixOptions?: CookiePrefixOptions;
|
|
48
50
|
};
|
|
49
51
|
headerName?: string;
|
|
52
|
+
alg: AsymmetricAlgorithm[];
|
|
50
53
|
verification?: VerifyOptions;
|
|
51
54
|
}, init?: RequestInit) => MiddlewareHandler;
|
|
@@ -19,7 +19,7 @@ export type JwtVariables<T = any> = {
|
|
|
19
19
|
* @param {object} options - The options for the JWT middleware.
|
|
20
20
|
* @param {SignatureKey} [options.secret] - A value of your secret key.
|
|
21
21
|
* @param {string} [options.cookie] - If this value is set, then the value is retrieved from the cookie header using that value as a key, which is then validated as a token.
|
|
22
|
-
* @param {SignatureAlgorithm}
|
|
22
|
+
* @param {SignatureAlgorithm} options.alg - An algorithm type that is used for verifying (required). Available types are `HS256` | `HS384` | `HS512` | `RS256` | `RS384` | `RS512` | `PS256` | `PS384` | `PS512` | `ES256` | `ES384` | `ES512` | `EdDSA`.
|
|
23
23
|
* @param {string} [options.headerName='Authorization'] - The name of the header to look for the JWT token. Default is 'Authorization'.
|
|
24
24
|
* @param {VerifyOptions} [options.verification] - Additional options for JWT payload verification.
|
|
25
25
|
* @returns {MiddlewareHandler} The middleware handler function.
|
|
@@ -32,6 +32,7 @@ export type JwtVariables<T = any> = {
|
|
|
32
32
|
* '/auth/*',
|
|
33
33
|
* jwt({
|
|
34
34
|
* secret: 'it-is-very-secret',
|
|
35
|
+
* alg: 'HS256',
|
|
35
36
|
* headerName: 'x-custom-auth-header', // Optional, default is 'Authorization'
|
|
36
37
|
* })
|
|
37
38
|
* )
|
|
@@ -48,7 +49,7 @@ export declare const jwt: (options: {
|
|
|
48
49
|
secret?: string | BufferSource;
|
|
49
50
|
prefixOptions?: CookiePrefixOptions;
|
|
50
51
|
};
|
|
51
|
-
alg
|
|
52
|
+
alg: SignatureAlgorithm;
|
|
52
53
|
headerName?: string;
|
|
53
54
|
verification?: VerifyOptions;
|
|
54
55
|
}) => MiddlewareHandler;
|
|
@@ -56,8 +57,9 @@ export declare const verifyWithJwks: (token: string, options: {
|
|
|
56
57
|
keys?: import("../../utils/jwt/jws").HonoJsonWebKey[];
|
|
57
58
|
jwks_uri?: string;
|
|
58
59
|
verification?: VerifyOptions;
|
|
60
|
+
allowedAlgorithms: import("../../utils/jwt/jwa").AsymmetricAlgorithm[];
|
|
59
61
|
}, init?: RequestInit) => Promise<import("../../utils/jwt/types").JWTPayload>;
|
|
60
|
-
export declare const verify: (token: string, publicKey: SignatureKey, algOrOptions
|
|
62
|
+
export declare const verify: (token: string, publicKey: SignatureKey, algOrOptions: SignatureAlgorithm | import("../../utils/jwt/jwt").VerifyOptionsWithAlg) => Promise<import("../../utils/jwt/types").JWTPayload>;
|
|
61
63
|
export declare const decode: (token: string) => {
|
|
62
64
|
header: import("../../utils/jwt/jwt").TokenHeader;
|
|
63
65
|
payload: import("../../utils/jwt/types").JWTPayload;
|
package/dist/types/types.d.ts
CHANGED
|
@@ -532,7 +532,8 @@ export type TypedResponse<T = unknown, U extends StatusCode = StatusCode, F exte
|
|
|
532
532
|
_format: F;
|
|
533
533
|
};
|
|
534
534
|
type MergeTypedResponse<T> = T extends Promise<void> ? T : T extends Promise<infer T2> ? T2 extends TypedResponse ? T2 : TypedResponse : T extends TypedResponse ? T : TypedResponse;
|
|
535
|
-
type
|
|
535
|
+
type ExtractTypedResponseOnly<T> = T extends TypedResponse ? T : never;
|
|
536
|
+
type MergeMiddlewareResponse<T> = T extends (c: any, next: any) => Promise<infer R> ? Exclude<R, void> extends never ? never : Exclude<R, void> extends Response | TypedResponse<any, any, any> ? ExtractTypedResponseOnly<Exclude<R, void>> : never : T extends (c: any, next: any) => infer R ? R extends Response | TypedResponse<any, any, any> ? ExtractTypedResponseOnly<R> : never : never;
|
|
536
537
|
export type FormValue = string | Blob;
|
|
537
538
|
export type ParsedFormValue = string | File;
|
|
538
539
|
export type ValidationTargets<T extends FormValue = ParsedFormValue, P extends string = string> = {
|
|
@@ -4,7 +4,7 @@
|
|
|
4
4
|
*/
|
|
5
5
|
export declare const Jwt: {
|
|
6
6
|
sign: (payload: import("./types").JWTPayload, privateKey: import("./jws").SignatureKey, alg?: import("./jwa").SignatureAlgorithm) => Promise<string>;
|
|
7
|
-
verify: (token: string, publicKey: import("./jws").SignatureKey, algOrOptions
|
|
7
|
+
verify: (token: string, publicKey: import("./jws").SignatureKey, algOrOptions: import("./jwa").SignatureAlgorithm | import("./jwt").VerifyOptionsWithAlg) => Promise<import("./types").JWTPayload>;
|
|
8
8
|
decode: (token: string) => {
|
|
9
9
|
header: import("./jwt").TokenHeader;
|
|
10
10
|
payload: import("./types").JWTPayload;
|
|
@@ -13,5 +13,6 @@ export declare const Jwt: {
|
|
|
13
13
|
keys?: import("./jws").HonoJsonWebKey[];
|
|
14
14
|
jwks_uri?: string;
|
|
15
15
|
verification?: import("./jwt").VerifyOptions;
|
|
16
|
+
allowedAlgorithms: import("./jwa").AsymmetricAlgorithm[];
|
|
16
17
|
}, init?: RequestInit) => Promise<import("./types").JWTPayload>;
|
|
17
18
|
};
|
|
@@ -19,3 +19,5 @@ export declare enum AlgorithmTypes {
|
|
|
19
19
|
EdDSA = "EdDSA"
|
|
20
20
|
}
|
|
21
21
|
export type SignatureAlgorithm = keyof typeof AlgorithmTypes;
|
|
22
|
+
export type SymmetricAlgorithm = 'HS256' | 'HS384' | 'HS512';
|
|
23
|
+
export type AsymmetricAlgorithm = 'RS256' | 'RS384' | 'RS512' | 'PS256' | 'PS384' | 'PS512' | 'ES256' | 'ES384' | 'ES512' | 'EdDSA';
|
|
@@ -3,7 +3,7 @@
|
|
|
3
3
|
* JSON Web Token (JWT)
|
|
4
4
|
* https://datatracker.ietf.org/doc/html/rfc7519
|
|
5
5
|
*/
|
|
6
|
-
import type { SignatureAlgorithm } from './jwa';
|
|
6
|
+
import type { AsymmetricAlgorithm, SignatureAlgorithm } from './jwa';
|
|
7
7
|
import type { HonoJsonWebKey, SignatureKey } from './jws';
|
|
8
8
|
import type { JWTPayload } from './types';
|
|
9
9
|
export interface TokenHeader {
|
|
@@ -27,13 +27,14 @@ export type VerifyOptions = {
|
|
|
27
27
|
};
|
|
28
28
|
export type VerifyOptionsWithAlg = {
|
|
29
29
|
/** The algorithm used for decoding the token */
|
|
30
|
-
alg
|
|
30
|
+
alg: SignatureAlgorithm;
|
|
31
31
|
} & VerifyOptions;
|
|
32
|
-
export declare const verify: (token: string, publicKey: SignatureKey, algOrOptions
|
|
32
|
+
export declare const verify: (token: string, publicKey: SignatureKey, algOrOptions: SignatureAlgorithm | VerifyOptionsWithAlg) => Promise<JWTPayload>;
|
|
33
33
|
export declare const verifyWithJwks: (token: string, options: {
|
|
34
34
|
keys?: HonoJsonWebKey[];
|
|
35
35
|
jwks_uri?: string;
|
|
36
36
|
verification?: VerifyOptions;
|
|
37
|
+
allowedAlgorithms: AsymmetricAlgorithm[];
|
|
37
38
|
}, init?: RequestInit) => Promise<JWTPayload>;
|
|
38
39
|
export declare const decode: (token: string) => {
|
|
39
40
|
header: TokenHeader;
|
|
@@ -5,6 +5,12 @@
|
|
|
5
5
|
export declare class JwtAlgorithmNotImplemented extends Error {
|
|
6
6
|
constructor(alg: string);
|
|
7
7
|
}
|
|
8
|
+
export declare class JwtAlgorithmRequired extends Error {
|
|
9
|
+
constructor();
|
|
10
|
+
}
|
|
11
|
+
export declare class JwtAlgorithmMismatch extends Error {
|
|
12
|
+
constructor(expected: string, actual: string);
|
|
13
|
+
}
|
|
8
14
|
export declare class JwtTokenInvalid extends Error {
|
|
9
15
|
constructor(token: string);
|
|
10
16
|
}
|
|
@@ -26,6 +32,12 @@ export declare class JwtHeaderInvalid extends Error {
|
|
|
26
32
|
export declare class JwtHeaderRequiresKid extends Error {
|
|
27
33
|
constructor(header: object);
|
|
28
34
|
}
|
|
35
|
+
export declare class JwtSymmetricAlgorithmNotAllowed extends Error {
|
|
36
|
+
constructor(alg: string);
|
|
37
|
+
}
|
|
38
|
+
export declare class JwtAlgorithmNotAllowed extends Error {
|
|
39
|
+
constructor(alg: string, allowedAlgorithms: string[]);
|
|
40
|
+
}
|
|
29
41
|
export declare class JwtTokenSignatureMismatched extends Error {
|
|
30
42
|
constructor(token: string);
|
|
31
43
|
}
|
package/dist/utils/jwt/jwt.js
CHANGED
|
@@ -3,9 +3,13 @@ import { decodeBase64Url, encodeBase64Url } from "../../utils/encode.js";
|
|
|
3
3
|
import { AlgorithmTypes } from "./jwa.js";
|
|
4
4
|
import { signing, verifying } from "./jws.js";
|
|
5
5
|
import {
|
|
6
|
+
JwtAlgorithmMismatch,
|
|
7
|
+
JwtAlgorithmNotAllowed,
|
|
8
|
+
JwtAlgorithmRequired,
|
|
6
9
|
JwtHeaderInvalid,
|
|
7
10
|
JwtHeaderRequiresKid,
|
|
8
11
|
JwtPayloadRequiresAud,
|
|
12
|
+
JwtSymmetricAlgorithmNotAllowed,
|
|
9
13
|
JwtTokenAudience,
|
|
10
14
|
JwtTokenExpired,
|
|
11
15
|
JwtTokenInvalid,
|
|
@@ -40,14 +44,20 @@ var sign = async (payload, privateKey, alg = "HS256") => {
|
|
|
40
44
|
return `${partialToken}.${signature}`;
|
|
41
45
|
};
|
|
42
46
|
var verify = async (token, publicKey, algOrOptions) => {
|
|
47
|
+
if (!algOrOptions) {
|
|
48
|
+
throw new JwtAlgorithmRequired();
|
|
49
|
+
}
|
|
43
50
|
const {
|
|
44
|
-
alg
|
|
51
|
+
alg,
|
|
45
52
|
iss,
|
|
46
53
|
nbf = true,
|
|
47
54
|
exp = true,
|
|
48
55
|
iat = true,
|
|
49
56
|
aud
|
|
50
|
-
} = typeof algOrOptions === "string" ? { alg: algOrOptions } : algOrOptions
|
|
57
|
+
} = typeof algOrOptions === "string" ? { alg: algOrOptions } : algOrOptions;
|
|
58
|
+
if (!alg) {
|
|
59
|
+
throw new JwtAlgorithmRequired();
|
|
60
|
+
}
|
|
51
61
|
const tokenParts = token.split(".");
|
|
52
62
|
if (tokenParts.length !== 3) {
|
|
53
63
|
throw new JwtTokenInvalid(token);
|
|
@@ -56,6 +66,9 @@ var verify = async (token, publicKey, algOrOptions) => {
|
|
|
56
66
|
if (!isTokenHeader(header)) {
|
|
57
67
|
throw new JwtHeaderInvalid(header);
|
|
58
68
|
}
|
|
69
|
+
if (header.alg !== alg) {
|
|
70
|
+
throw new JwtAlgorithmMismatch(alg, header.alg);
|
|
71
|
+
}
|
|
59
72
|
const now = Date.now() / 1e3 | 0;
|
|
60
73
|
if (nbf && payload.nbf && payload.nbf > now) {
|
|
61
74
|
throw new JwtTokenNotBefore(token);
|
|
@@ -101,6 +114,11 @@ var verify = async (token, publicKey, algOrOptions) => {
|
|
|
101
114
|
}
|
|
102
115
|
return payload;
|
|
103
116
|
};
|
|
117
|
+
var symmetricAlgorithms = [
|
|
118
|
+
AlgorithmTypes.HS256,
|
|
119
|
+
AlgorithmTypes.HS384,
|
|
120
|
+
AlgorithmTypes.HS512
|
|
121
|
+
];
|
|
104
122
|
var verifyWithJwks = async (token, options, init) => {
|
|
105
123
|
const verifyOpts = options.verification || {};
|
|
106
124
|
const header = decodeHeader(token);
|
|
@@ -110,6 +128,12 @@ var verifyWithJwks = async (token, options, init) => {
|
|
|
110
128
|
if (!header.kid) {
|
|
111
129
|
throw new JwtHeaderRequiresKid(header);
|
|
112
130
|
}
|
|
131
|
+
if (symmetricAlgorithms.includes(header.alg)) {
|
|
132
|
+
throw new JwtSymmetricAlgorithmNotAllowed(header.alg);
|
|
133
|
+
}
|
|
134
|
+
if (!options.allowedAlgorithms.includes(header.alg)) {
|
|
135
|
+
throw new JwtAlgorithmNotAllowed(header.alg, options.allowedAlgorithms);
|
|
136
|
+
}
|
|
113
137
|
if (options.jwks_uri) {
|
|
114
138
|
const response = await fetch(options.jwks_uri, init);
|
|
115
139
|
if (!response.ok) {
|
|
@@ -134,8 +158,11 @@ var verifyWithJwks = async (token, options, init) => {
|
|
|
134
158
|
if (!matchingKey) {
|
|
135
159
|
throw new JwtTokenInvalid(token);
|
|
136
160
|
}
|
|
161
|
+
if (matchingKey.alg && matchingKey.alg !== header.alg) {
|
|
162
|
+
throw new JwtAlgorithmMismatch(matchingKey.alg, header.alg);
|
|
163
|
+
}
|
|
137
164
|
return await verify(token, matchingKey, {
|
|
138
|
-
alg:
|
|
165
|
+
alg: header.alg,
|
|
139
166
|
...verifyOpts
|
|
140
167
|
});
|
|
141
168
|
};
|
package/dist/utils/jwt/types.js
CHANGED
|
@@ -5,6 +5,18 @@ var JwtAlgorithmNotImplemented = class extends Error {
|
|
|
5
5
|
this.name = "JwtAlgorithmNotImplemented";
|
|
6
6
|
}
|
|
7
7
|
};
|
|
8
|
+
var JwtAlgorithmRequired = class extends Error {
|
|
9
|
+
constructor() {
|
|
10
|
+
super('JWT verification requires "alg" option to be specified');
|
|
11
|
+
this.name = "JwtAlgorithmRequired";
|
|
12
|
+
}
|
|
13
|
+
};
|
|
14
|
+
var JwtAlgorithmMismatch = class extends Error {
|
|
15
|
+
constructor(expected, actual) {
|
|
16
|
+
super(`JWT algorithm mismatch: expected "${expected}", got "${actual}"`);
|
|
17
|
+
this.name = "JwtAlgorithmMismatch";
|
|
18
|
+
}
|
|
19
|
+
};
|
|
8
20
|
var JwtTokenInvalid = class extends Error {
|
|
9
21
|
constructor(token) {
|
|
10
22
|
super(`invalid JWT token: ${token}`);
|
|
@@ -49,6 +61,18 @@ var JwtHeaderRequiresKid = class extends Error {
|
|
|
49
61
|
this.name = "JwtHeaderRequiresKid";
|
|
50
62
|
}
|
|
51
63
|
};
|
|
64
|
+
var JwtSymmetricAlgorithmNotAllowed = class extends Error {
|
|
65
|
+
constructor(alg) {
|
|
66
|
+
super(`symmetric algorithm "${alg}" is not allowed for JWK verification`);
|
|
67
|
+
this.name = "JwtSymmetricAlgorithmNotAllowed";
|
|
68
|
+
}
|
|
69
|
+
};
|
|
70
|
+
var JwtAlgorithmNotAllowed = class extends Error {
|
|
71
|
+
constructor(alg, allowedAlgorithms) {
|
|
72
|
+
super(`algorithm "${alg}" is not in the allowed list: [${allowedAlgorithms.join(", ")}]`);
|
|
73
|
+
this.name = "JwtAlgorithmNotAllowed";
|
|
74
|
+
}
|
|
75
|
+
};
|
|
52
76
|
var JwtTokenSignatureMismatched = class extends Error {
|
|
53
77
|
constructor(token) {
|
|
54
78
|
super(`token(${token}) signature mismatched`);
|
|
@@ -82,10 +106,14 @@ var CryptoKeyUsage = /* @__PURE__ */ ((CryptoKeyUsage2) => {
|
|
|
82
106
|
})(CryptoKeyUsage || {});
|
|
83
107
|
export {
|
|
84
108
|
CryptoKeyUsage,
|
|
109
|
+
JwtAlgorithmMismatch,
|
|
110
|
+
JwtAlgorithmNotAllowed,
|
|
85
111
|
JwtAlgorithmNotImplemented,
|
|
112
|
+
JwtAlgorithmRequired,
|
|
86
113
|
JwtHeaderInvalid,
|
|
87
114
|
JwtHeaderRequiresKid,
|
|
88
115
|
JwtPayloadRequiresAud,
|
|
116
|
+
JwtSymmetricAlgorithmNotAllowed,
|
|
89
117
|
JwtTokenAudience,
|
|
90
118
|
JwtTokenExpired,
|
|
91
119
|
JwtTokenInvalid,
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "hono",
|
|
3
|
-
"version": "4.11.
|
|
3
|
+
"version": "4.11.4",
|
|
4
4
|
"description": "Web framework built on Web Standards",
|
|
5
5
|
"main": "dist/cjs/index.js",
|
|
6
6
|
"type": "module",
|
|
@@ -656,7 +656,7 @@
|
|
|
656
656
|
"nodejs"
|
|
657
657
|
],
|
|
658
658
|
"devDependencies": {
|
|
659
|
-
"@hono/eslint-config": "^2.0.
|
|
659
|
+
"@hono/eslint-config": "^2.0.5",
|
|
660
660
|
"@hono/node-server": "^1.13.5",
|
|
661
661
|
"@types/glob": "^9.0.0",
|
|
662
662
|
"@types/jsdom": "^21.1.7",
|