@alanszp/express 6.0.4 → 7.0.1

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.
Files changed (47) hide show
  1. package/.env.test +5 -0
  2. package/babel.config.js +7 -0
  3. package/dist/helpers/now.d.ts +1 -0
  4. package/dist/helpers/now.js +8 -0
  5. package/dist/helpers/now.js.map +1 -0
  6. package/dist/index.d.ts +1 -1
  7. package/dist/index.js +1 -1
  8. package/dist/index.js.map +1 -1
  9. package/dist/middlewares/authenticateUser.d.ts +25 -0
  10. package/dist/middlewares/authenticateUser.js +114 -0
  11. package/dist/middlewares/authenticateUser.js.map +1 -0
  12. package/dist/middlewares/authenticateUser.test.d.ts +1 -0
  13. package/dist/middlewares/authenticateUser.test.js +308 -0
  14. package/dist/middlewares/authenticateUser.test.js.map +1 -0
  15. package/dist/test/mocks/authOptionsMocks.d.ts +8 -0
  16. package/dist/test/mocks/authOptionsMocks.js +30 -0
  17. package/dist/test/mocks/authOptionsMocks.js.map +1 -0
  18. package/dist/test/mocks/expressMocks.d.ts +5 -0
  19. package/dist/test/mocks/expressMocks.js +20 -0
  20. package/dist/test/mocks/expressMocks.js.map +1 -0
  21. package/dist/test/mocks/jwtUserMocks.d.ts +3 -0
  22. package/dist/test/mocks/jwtUserMocks.js +18 -0
  23. package/dist/test/mocks/jwtUserMocks.js.map +1 -0
  24. package/dist/test/setup.d.ts +1 -0
  25. package/dist/test/setup.js +5 -0
  26. package/dist/test/setup.js.map +1 -0
  27. package/dist/test/setup.test.d.ts +1 -0
  28. package/dist/test/setup.test.js +14 -0
  29. package/dist/test/setup.test.js.map +1 -0
  30. package/dist/types/AuthMethod.d.ts +1 -1
  31. package/jest.config.js +10 -0
  32. package/package.json +12 -7
  33. package/src/helpers/now.ts +3 -0
  34. package/src/index.ts +1 -1
  35. package/src/middlewares/authenticateUser.test.ts +403 -0
  36. package/src/middlewares/authenticateUser.ts +170 -0
  37. package/src/test/mocks/authOptionsMocks.ts +35 -0
  38. package/src/test/mocks/expressMocks.ts +17 -0
  39. package/src/test/mocks/jwtUserMocks.ts +17 -0
  40. package/src/test/setup.test.ts +15 -0
  41. package/src/test/setup.ts +3 -0
  42. package/src/types/AuthMethod.ts +4 -1
  43. package/tsconfig.json +5 -2
  44. package/dist/middlewares/authWithJWT.d.ts +0 -4
  45. package/dist/middlewares/authWithJWT.js +0 -56
  46. package/dist/middlewares/authWithJWT.js.map +0 -1
  47. package/src/middlewares/authWithJWT.ts +0 -54
@@ -0,0 +1,18 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.laraJwtUserMock = exports.userJwtUserMock = void 0;
4
+ exports.userJwtUserMock = {
5
+ id: "1",
6
+ employeeReference: "1",
7
+ organizationReference: "test",
8
+ roles: [],
9
+ permissions: [],
10
+ };
11
+ exports.laraJwtUserMock = {
12
+ id: "0",
13
+ employeeReference: "0",
14
+ organizationReference: "lara",
15
+ roles: [],
16
+ permissions: [],
17
+ };
18
+ //# sourceMappingURL=jwtUserMocks.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"jwtUserMocks.js","sourceRoot":"","sources":["../../../src/test/mocks/jwtUserMocks.ts"],"names":[],"mappings":";;;AAEa,QAAA,eAAe,GAAY;IACtC,EAAE,EAAE,GAAG;IACP,iBAAiB,EAAE,GAAG;IACtB,qBAAqB,EAAE,MAAM;IAC7B,KAAK,EAAE,EAAE;IACT,WAAW,EAAE,EAAE;CAChB,CAAC;AAEW,QAAA,eAAe,GAAY;IACtC,EAAE,EAAE,GAAG;IACP,iBAAiB,EAAE,GAAG;IACtB,qBAAqB,EAAE,MAAM;IAC7B,KAAK,EAAE,EAAE;IACT,WAAW,EAAE,EAAE;CAChB,CAAC"}
@@ -0,0 +1 @@
1
+ export {};
@@ -0,0 +1,5 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ const dotenv_1 = require("dotenv");
4
+ (0, dotenv_1.config)({ path: ".env.test" });
5
+ //# sourceMappingURL=setup.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"setup.js","sourceRoot":"","sources":["../../src/test/setup.ts"],"names":[],"mappings":";;AAAA,mCAAgC;AAEhC,IAAA,eAAM,EAAC,EAAE,IAAI,EAAE,WAAW,EAAE,CAAC,CAAC"}
@@ -0,0 +1 @@
1
+ export {};
@@ -0,0 +1,14 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ const now_1 = require("../helpers/now");
4
+ jest.mock("@/helpers/now");
5
+ describe("Timezones", () => {
6
+ it("should always be UTC", () => {
7
+ expect(new Date().getTimezoneOffset()).toBe(0);
8
+ });
9
+ it("now() is mocked", () => {
10
+ now_1.now.mockReturnValue(new Date("2021-01-01T12:30:43"));
11
+ expect((0, now_1.now)()).toEqual(new Date("2021-01-01T12:30:43"));
12
+ });
13
+ });
14
+ //# sourceMappingURL=setup.test.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"setup.test.js","sourceRoot":"","sources":["../../src/test/setup.test.ts"],"names":[],"mappings":";;AAAA,wCAAqC;AAErC,IAAI,CAAC,IAAI,CAAC,eAAe,CAAC,CAAC;AAE3B,QAAQ,CAAC,WAAW,EAAE,GAAG,EAAE;IACzB,EAAE,CAAC,sBAAsB,EAAE,GAAG,EAAE;QAC9B,MAAM,CAAC,IAAI,IAAI,EAAE,CAAC,iBAAiB,EAAE,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;IACjD,CAAC,CAAC,CAAC;IAEH,EAAE,CAAC,iBAAiB,EAAE,GAAG,EAAE;QACxB,SAAiB,CAAC,eAAe,CAAC,IAAI,IAAI,CAAC,qBAAqB,CAAC,CAAC,CAAC;QAEpE,MAAM,CAAC,IAAA,SAAG,GAAE,CAAC,CAAC,OAAO,CAAC,IAAI,IAAI,CAAC,qBAAqB,CAAC,CAAC,CAAC;IACzD,CAAC,CAAC,CAAC;AACL,CAAC,CAAC,CAAC"}
@@ -6,5 +6,5 @@ declare type GenerateStringUnion<T> = Extract<{
6
6
  declare type OverridableStringUnion<T extends string | number, U = {}> = GenerateStringUnion<Overwrite<Record<T, true>, U>>;
7
7
  export interface AuthMethodsOverride {
8
8
  }
9
- export declare type AuthMethod = OverridableStringUnion<"jwt", AuthMethodsOverride>;
9
+ export declare type AuthMethod = OverridableStringUnion<"jwt" | "api_key", AuthMethodsOverride>;
10
10
  export {};
package/jest.config.js ADDED
@@ -0,0 +1,10 @@
1
+ module.exports = {
2
+ collectCoverageFrom: ["src/**/*.{js,jsx,ts,tsx}"],
3
+ roots: ["<rootDir>/src/"],
4
+ clearMocks: true,
5
+ resetMocks: true,
6
+ testEnvironment: "node",
7
+ moduleNameMapper: {
8
+ "@/(.*)": "<rootDir>/src/$1",
9
+ },
10
+ };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@alanszp/express",
3
- "version": "6.0.4",
3
+ "version": "7.0.1",
4
4
  "description": "Alan's express utils and middlewares.",
5
5
  "main": "dist/index.js",
6
6
  "typings": "dist/index.d.ts",
@@ -14,6 +14,7 @@
14
14
  "scripts": {
15
15
  "compile": "rm -rf ./dist && tsc --declaration",
16
16
  "compile-watch": "tsc -w",
17
+ "test": "TZ=Etc/UTC jest",
17
18
  "build": "yarn run compile",
18
19
  "prepack": "yarn run build",
19
20
  "yalc-publish": "yarn run yalc publish"
@@ -24,21 +25,25 @@
24
25
  "devDependencies": {
25
26
  "@types/body-parser": "^1.19.1",
26
27
  "@types/express": "^4.17.12",
28
+ "@types/jest": "^28.1.8",
27
29
  "@types/lodash": "^4.14.170",
28
30
  "@types/node": "^15.12.3",
31
+ "babel-jest": "^29.0.0",
32
+ "eslint-plugin-jest": "^26.8.7",
33
+ "jest": "^29.0.0",
29
34
  "ts-node": "^10.0.0",
30
35
  "tslint": "^6.1.3",
31
36
  "typescript": "^4.3.4"
32
37
  },
33
38
  "dependencies": {
34
- "@alanszp/audit": "^6.0.0",
35
- "@alanszp/errors": "^6.0.0",
36
- "@alanszp/jwt": "^6.0.0",
37
- "@alanszp/logger": "^6.0.0",
38
- "@alanszp/shared-context": "^6.0.4",
39
+ "@alanszp/audit": "^7.0.0",
40
+ "@alanszp/errors": "^7.0.0",
41
+ "@alanszp/jwt": "^7.0.0",
42
+ "@alanszp/logger": "^7.0.0",
43
+ "@alanszp/shared-context": "^7.0.0",
39
44
  "body-parser": "^1.19.0",
40
45
  "cuid": "^2.1.8",
41
46
  "lodash": "^4.17.21"
42
47
  },
43
- "gitHead": "f11faa4b3583d683efc45e30d0817e4d3a9786a2"
48
+ "gitHead": "67e6ad3d56d02ee10f45ca59f7e68bc77d574f41"
44
49
  }
@@ -0,0 +1,3 @@
1
+ export function now(): Date {
2
+ return new Date();
3
+ }
package/src/index.ts CHANGED
@@ -4,7 +4,7 @@ export * from "./middlewares/auditLog";
4
4
  export * from "./middlewares/accessLogger";
5
5
  export * from "./middlewares/authedForOrg";
6
6
  export * from "./middlewares/createContext";
7
- export * from "./middlewares/authWithJWT";
7
+ export * from "./middlewares/authenticateUser";
8
8
  export * from "./middlewares/returnInternalServerError";
9
9
  export * from "./middlewares/returnNotFound";
10
10
  export * from "./middlewares/jsonBodyParser";
@@ -0,0 +1,403 @@
1
+ import { AuthMethods, createAuthContext } from "./authenticateUser";
2
+ import { verifyJWT } from "@alanszp/jwt";
3
+ import {
4
+ mockNext,
5
+ mockRequest,
6
+ mockResponse,
7
+ } from "../test/mocks/expressMocks";
8
+ import { laraJwtUserMock, userJwtUserMock } from "../test/mocks/jwtUserMocks";
9
+ import {
10
+ apiKeyAuthOptions,
11
+ bothMethodsAuthOptions,
12
+ jwtAuthOptions,
13
+ verifyOptions,
14
+ } from "../test/mocks/authOptionsMocks";
15
+
16
+ jest.mock("@alanszp/jwt");
17
+
18
+ describe("AuthenticateUser", () => {
19
+ describe("authentication with only JWT", () => {
20
+ describe("when jwt verifies correctly", () => {
21
+ it("should authenticate correctly and call next", async () => {
22
+ (verifyJWT as jest.Mock).mockResolvedValueOnce(userJwtUserMock);
23
+
24
+ const req = mockRequest("Bearer token");
25
+ const res = mockResponse();
26
+ const next = mockNext();
27
+
28
+ await createAuthContext(jwtAuthOptions)([AuthMethods.JWT])(
29
+ req,
30
+ res,
31
+ next
32
+ );
33
+
34
+ expect(verifyJWT).toBeCalledWith("publicKey", "token", verifyOptions);
35
+ expect(res.status).toHaveBeenCalledTimes(0);
36
+ expect(res.json).toHaveBeenCalledTimes(0);
37
+ expect(req.context.jwtUser).toMatchObject(userJwtUserMock);
38
+ expect(req.context.authenticated).toStrictEqual(["jwt"]);
39
+ expect(next).toBeCalledWith();
40
+ });
41
+ });
42
+
43
+ describe("when jwt verifies incorrectly", () => {
44
+ it("should not authenticate, should not call next, and it should return 401", async () => {
45
+ (verifyJWT as jest.Mock).mockResolvedValueOnce(undefined);
46
+
47
+ const req = mockRequest("Bearer token");
48
+ const res = mockResponse();
49
+ const next = mockNext();
50
+
51
+ await createAuthContext(jwtAuthOptions)([AuthMethods.JWT])(
52
+ req,
53
+ res,
54
+ next
55
+ );
56
+
57
+ expect(verifyJWT).toBeCalledWith("publicKey", "token", verifyOptions);
58
+ expect(res.status).toHaveBeenCalledWith(401);
59
+ expect(res.json).toHaveBeenCalledTimes(1);
60
+ expect(req.context.jwtUser).toBe(undefined);
61
+ expect(req.context.authenticated).toEqual([]);
62
+ expect(next).toHaveBeenCalledTimes(0);
63
+ });
64
+ });
65
+
66
+ describe("when jwt doesn't exist", () => {
67
+ it("should not verify JWT, should not authenticate, should not call next, and it should return 401", async () => {
68
+ const req = mockRequest("aa");
69
+ const res = mockResponse();
70
+ const next = mockNext();
71
+
72
+ await createAuthContext(jwtAuthOptions)([AuthMethods.JWT])(
73
+ req,
74
+ res,
75
+ next
76
+ );
77
+
78
+ expect(verifyJWT).toHaveBeenCalledTimes(0);
79
+ expect(res.status).toHaveBeenCalledWith(401);
80
+ expect(res.json).toHaveBeenCalledTimes(1);
81
+ expect(req.context.jwtUser).toBe(undefined);
82
+ expect(req.context.authenticated).toEqual([]);
83
+ expect(next).toHaveBeenCalledTimes(0);
84
+ });
85
+ });
86
+ });
87
+
88
+ describe("authentication with only API KEY", () => {
89
+ describe("when api key verifies correctly", () => {
90
+ it("should authenticate correctly and call next", async () => {
91
+ const req = mockRequest("token");
92
+ const res = mockResponse();
93
+ const next = mockNext();
94
+
95
+ await createAuthContext(apiKeyAuthOptions)([AuthMethods.API_KEY])(
96
+ req,
97
+ res,
98
+ next
99
+ );
100
+
101
+ expect(verifyJWT).toHaveBeenCalledTimes(0);
102
+ expect(res.status).toHaveBeenCalledTimes(0);
103
+ expect(res.json).toHaveBeenCalledTimes(0);
104
+ expect(req.context.jwtUser).toMatchObject(laraJwtUserMock);
105
+ expect(req.context.authenticated).toStrictEqual(["api_key"]);
106
+ expect(next).toBeCalledWith();
107
+ });
108
+ });
109
+
110
+ describe("when api key verifies incorrectly", () => {
111
+ it("should not authenticate, should not call next, and it should return 401", async () => {
112
+ const req = mockRequest("invalidToken");
113
+ const res = mockResponse();
114
+ const next = mockNext();
115
+
116
+ await createAuthContext(apiKeyAuthOptions)([AuthMethods.API_KEY])(
117
+ req,
118
+ res,
119
+ next
120
+ );
121
+
122
+ expect(verifyJWT).toHaveBeenCalledTimes(0);
123
+ expect(res.status).toHaveBeenCalledWith(401);
124
+ expect(res.json).toHaveBeenCalledTimes(1);
125
+ expect(req.context.jwtUser).toBe(undefined);
126
+ expect(req.context.authenticated).toEqual([]);
127
+ expect(next).toHaveBeenCalledTimes(0);
128
+ });
129
+ });
130
+
131
+ describe("when api key doesn't exist", () => {
132
+ it("should not verify api key, should not authenticate, should not call next, and it should return 401", async () => {
133
+ const req = mockRequest(undefined as any);
134
+ const res = mockResponse();
135
+ const next = mockNext();
136
+
137
+ await createAuthContext(apiKeyAuthOptions)([AuthMethods.API_KEY])(
138
+ req,
139
+ res,
140
+ next
141
+ );
142
+
143
+ expect(verifyJWT).toHaveBeenCalledTimes(0);
144
+ expect(res.status).toHaveBeenCalledWith(401);
145
+ expect(res.json).toHaveBeenCalledTimes(1);
146
+ expect(req.context.jwtUser).toBe(undefined);
147
+ expect(req.context.authenticated).toEqual([]);
148
+ expect(next).toHaveBeenCalledTimes(0);
149
+ });
150
+ });
151
+ });
152
+
153
+ describe("authentication with JWT and API KEY", () => {
154
+ describe("using both methods", () => {
155
+ describe("when api key verifies correctly", () => {
156
+ it("should authenticate correctly and call next", async () => {
157
+ const req = mockRequest("token");
158
+ const res = mockResponse();
159
+ const next = mockNext();
160
+
161
+ await createAuthContext(bothMethodsAuthOptions)([
162
+ AuthMethods.API_KEY,
163
+ AuthMethods.JWT,
164
+ ])(req, res, next);
165
+
166
+ expect(verifyJWT).toHaveBeenCalledTimes(0);
167
+ expect(res.status).toHaveBeenCalledTimes(0);
168
+ expect(res.json).toHaveBeenCalledTimes(0);
169
+ expect(req.context.jwtUser).toMatchObject(laraJwtUserMock);
170
+ expect(req.context.authenticated).toStrictEqual(["api_key"]);
171
+ expect(next).toHaveBeenCalledWith();
172
+ });
173
+ });
174
+
175
+ describe("when api key verifies incorrectly", () => {
176
+ it("should not authenticate, should not call next, and it should return 401", async () => {
177
+ const req = mockRequest("invalidToken");
178
+ const res = mockResponse();
179
+ const next = mockNext();
180
+
181
+ await createAuthContext(bothMethodsAuthOptions)([
182
+ AuthMethods.API_KEY,
183
+ AuthMethods.JWT,
184
+ ])(req, res, next);
185
+
186
+ expect(verifyJWT).toHaveBeenCalledTimes(0);
187
+ expect(res.status).toHaveBeenCalledWith(401);
188
+ expect(res.json).toHaveBeenCalledTimes(1);
189
+ expect(req.context.jwtUser).toBe(undefined);
190
+ expect(req.context.authenticated).toEqual([]);
191
+ expect(next).toHaveBeenCalledTimes(0);
192
+ });
193
+ });
194
+
195
+ describe("when jwt verifies correctly", () => {
196
+ it("should authenticate correctly and call next", async () => {
197
+ (verifyJWT as jest.Mock).mockResolvedValueOnce(userJwtUserMock);
198
+
199
+ const req = mockRequest("Bearer token");
200
+ const res = mockResponse();
201
+ const next = mockNext();
202
+
203
+ await createAuthContext(bothMethodsAuthOptions)([
204
+ AuthMethods.API_KEY,
205
+ AuthMethods.JWT,
206
+ ])(req, res, next);
207
+
208
+ expect(verifyJWT).toBeCalledWith("publicKey", "token", {
209
+ issuer: "issuer",
210
+ audience: "audience",
211
+ });
212
+ expect(res.status).toHaveBeenCalledTimes(0);
213
+ expect(res.json).toHaveBeenCalledTimes(0);
214
+
215
+ expect(req.context.jwtUser).toMatchObject(userJwtUserMock);
216
+
217
+ expect(req.context.authenticated).toStrictEqual(["jwt"]);
218
+
219
+ expect(next).toHaveBeenCalledWith();
220
+ });
221
+ });
222
+
223
+ describe("when jwt verifies incorrectly", () => {
224
+ it("should not authenticate, should not call next, and it should return 401", async () => {
225
+ (verifyJWT as jest.Mock).mockResolvedValueOnce(undefined);
226
+
227
+ const req = mockRequest("Bearer token");
228
+ const res = mockResponse();
229
+ const next = mockNext();
230
+
231
+ await createAuthContext(bothMethodsAuthOptions)([
232
+ AuthMethods.API_KEY,
233
+ AuthMethods.JWT,
234
+ ])(req, res, next);
235
+
236
+ expect(verifyJWT).toBeCalledWith("publicKey", "token", {
237
+ issuer: "issuer",
238
+ audience: "audience",
239
+ });
240
+ expect(res.status).toHaveBeenCalledWith(401);
241
+ expect(res.json).toHaveBeenCalledTimes(1);
242
+ expect(req.context.jwtUser).toBe(undefined);
243
+ expect(req.context.authenticated).toEqual([]);
244
+ expect(next).toHaveBeenCalledTimes(0);
245
+ });
246
+ });
247
+
248
+ describe("when jwt doesnt exist", () => {
249
+ it("should not authenticate, should not call next, and it should return 401", async () => {
250
+ const req = mockRequest(undefined as any);
251
+ const res = mockResponse();
252
+ const next = mockNext();
253
+
254
+ await createAuthContext(bothMethodsAuthOptions)([
255
+ AuthMethods.API_KEY,
256
+ AuthMethods.JWT,
257
+ ])(req, res, next);
258
+
259
+ expect(verifyJWT).toHaveBeenCalledTimes(0);
260
+ expect(res.status).toHaveBeenCalledWith(401);
261
+ expect(res.json).toHaveBeenCalledTimes(1);
262
+ expect(req.context.jwtUser).toBe(undefined);
263
+ expect(req.context.authenticated).toEqual([]);
264
+ expect(next).toHaveBeenCalledTimes(0);
265
+ });
266
+ });
267
+ });
268
+
269
+ describe("using jwt method", () => {
270
+ describe("when jwt verifies correctly", () => {
271
+ it("should authenticate correctly and call next", async () => {
272
+ (verifyJWT as jest.Mock).mockResolvedValueOnce(userJwtUserMock);
273
+
274
+ const req = mockRequest("Bearer token");
275
+ const res = mockResponse();
276
+ const next = mockNext();
277
+
278
+ await createAuthContext(bothMethodsAuthOptions)([AuthMethods.JWT])(
279
+ req,
280
+ res,
281
+ next
282
+ );
283
+
284
+ expect(verifyJWT).toBeCalledWith("publicKey", "token", {
285
+ issuer: "issuer",
286
+ audience: "audience",
287
+ });
288
+ expect(res.status).toHaveBeenCalledTimes(0);
289
+ expect(res.json).toHaveBeenCalledTimes(0);
290
+ expect(req.context.jwtUser).toMatchObject(userJwtUserMock);
291
+ expect(req.context.authenticated).toStrictEqual(["jwt"]);
292
+ expect(next).toHaveBeenCalledWith();
293
+ });
294
+ });
295
+
296
+ describe("when jwt verifies incorrectly", () => {
297
+ it("should not authenticate, should not call next, and it should return 401", async () => {
298
+ (verifyJWT as jest.Mock).mockResolvedValueOnce(undefined);
299
+
300
+ const req = mockRequest("Bearer invalidToken");
301
+ const res = mockResponse();
302
+ const next = mockNext();
303
+
304
+ await createAuthContext(bothMethodsAuthOptions)([AuthMethods.JWT])(
305
+ req,
306
+ res,
307
+ next
308
+ );
309
+
310
+ expect(verifyJWT).toBeCalledWith("publicKey", "invalidToken", {
311
+ issuer: "issuer",
312
+ audience: "audience",
313
+ });
314
+ expect(res.status).toHaveBeenCalledWith(401);
315
+ expect(res.json).toHaveBeenCalledTimes(1);
316
+ expect(req.context.jwtUser).toBe(undefined);
317
+ expect(req.context.authenticated).toEqual([]);
318
+ expect(next).toHaveBeenCalledTimes(0);
319
+ });
320
+ });
321
+
322
+ describe("when api key verifies correctly", () => {
323
+ it("should authenticate correctly and call next", async () => {
324
+ const req = mockRequest("token");
325
+ const res = mockResponse();
326
+ const next = mockNext();
327
+
328
+ await createAuthContext(bothMethodsAuthOptions)([
329
+ AuthMethods.API_KEY,
330
+ ])(req, res, next);
331
+
332
+ expect(verifyJWT).toHaveBeenCalledTimes(0);
333
+ expect(res.status).toHaveBeenCalledTimes(0);
334
+ expect(res.json).toHaveBeenCalledTimes(0);
335
+
336
+ expect(req.context.jwtUser).toMatchObject(laraJwtUserMock);
337
+ expect(req.context.authenticated).toStrictEqual(["api_key"]);
338
+ expect(next).toHaveBeenCalledWith();
339
+ });
340
+ });
341
+
342
+ describe("when api key verifies incorrectly", () => {
343
+ it("should not authenticate, should not call next, and it should return 401", async () => {
344
+ const req = mockRequest("invalidToken");
345
+ const res = mockResponse();
346
+ const next = mockNext();
347
+
348
+ await createAuthContext(bothMethodsAuthOptions)([
349
+ AuthMethods.API_KEY,
350
+ AuthMethods.JWT,
351
+ ])(req, res, next);
352
+
353
+ expect(verifyJWT).toHaveBeenCalledTimes(0);
354
+ expect(res.status).toHaveBeenCalledWith(401);
355
+ expect(res.json).toHaveBeenCalledTimes(1);
356
+ expect(req.context.jwtUser).toBe(undefined);
357
+ expect(req.context.authenticated).toEqual([]);
358
+ expect(next).toHaveBeenCalledTimes(0);
359
+ });
360
+ });
361
+
362
+ describe("when jwt doesnt exist", () => {
363
+ it("should not authenticate, should not call next, and it should return 401", async () => {
364
+ const req = mockRequest("aaa");
365
+ const res = mockResponse();
366
+ const next = mockNext();
367
+
368
+ await createAuthContext(bothMethodsAuthOptions)([AuthMethods.JWT])(
369
+ req,
370
+ res,
371
+ next
372
+ );
373
+
374
+ expect(verifyJWT).toHaveBeenCalledTimes(0);
375
+ expect(res.status).toHaveBeenCalledWith(401);
376
+ expect(res.json).toHaveBeenCalledTimes(1);
377
+ expect(req.context.jwtUser).toBe(undefined);
378
+ expect(req.context.authenticated).toEqual([]);
379
+ expect(next).toHaveBeenCalledTimes(0);
380
+ });
381
+ });
382
+
383
+ describe("when api key doesnt exist", () => {
384
+ it("should not authenticate, should not call next, and it should return 401", async () => {
385
+ const req = mockRequest(undefined as any);
386
+ const res = mockResponse();
387
+ const next = mockNext();
388
+
389
+ await createAuthContext(bothMethodsAuthOptions)([
390
+ AuthMethods.API_KEY,
391
+ ])(req, res, next);
392
+
393
+ expect(verifyJWT).toHaveBeenCalledTimes(0);
394
+ expect(res.status).toHaveBeenCalledWith(401);
395
+ expect(res.json).toHaveBeenCalledTimes(1);
396
+ expect(req.context.jwtUser).toBe(undefined);
397
+ expect(req.context.authenticated).toEqual([]);
398
+ expect(next).toHaveBeenCalledTimes(0);
399
+ });
400
+ });
401
+ });
402
+ });
403
+ });