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.
@@ -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(token, { keys, jwks_uri, verification: verifyOpts }, init);
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 = "HS256",
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: matchingKey.alg || header.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(token, { keys, jwks_uri, verification: verifyOpts }, init);
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 `createWebSocket` and `websocket` directly from `hono/bun` instead.
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} [options.alg=HS256] - An algorithm type that is used for verifying. Available types are `HS256` | `HS384` | `HS512` | `RS256` | `RS384` | `RS512` | `PS256` | `PS384` | `PS512` | `ES256` | `ES384` | `ES512` | `EdDSA`.
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?: SignatureAlgorithm;
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?: SignatureAlgorithm | import("../../utils/jwt/jwt").VerifyOptionsWithAlg) => Promise<import("../../utils/jwt/types").JWTPayload>;
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;
@@ -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 MergeMiddlewareResponse<T> = T extends (c: any, next: any) => Promise<infer R> ? Exclude<R, void> extends never ? never : Exclude<R, void> extends TypedResponse ? Exclude<R, void> : never : T extends (c: any, next: any) => infer R ? R extends TypedResponse ? R : never : never;
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?: import("./jwa").SignatureAlgorithm | import("./jwt").VerifyOptionsWithAlg) => Promise<import("./types").JWTPayload>;
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?: SignatureAlgorithm;
30
+ alg: SignatureAlgorithm;
31
31
  } & VerifyOptions;
32
- export declare const verify: (token: string, publicKey: SignatureKey, algOrOptions?: SignatureAlgorithm | VerifyOptionsWithAlg) => Promise<JWTPayload>;
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
  }
@@ -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 = "HS256",
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: matchingKey.alg || header.alg,
165
+ alg: header.alg,
139
166
  ...verifyOpts
140
167
  });
141
168
  };
@@ -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.2",
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.3",
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",