@easyweb/authentication 1.0.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.
Files changed (54) hide show
  1. package/README.md +100 -0
  2. package/dist/errors/bad-request-error.d.ts +10 -0
  3. package/dist/errors/bad-request-error.d.ts.map +1 -0
  4. package/dist/errors/bad-request-error.js +16 -0
  5. package/dist/errors/bad-request-error.js.map +1 -0
  6. package/dist/errors/custom-error.d.ts +9 -0
  7. package/dist/errors/custom-error.d.ts.map +1 -0
  8. package/dist/errors/custom-error.js +11 -0
  9. package/dist/errors/custom-error.js.map +1 -0
  10. package/dist/errors/database-connection-error.d.ts +10 -0
  11. package/dist/errors/database-connection-error.d.ts.map +1 -0
  12. package/dist/errors/database-connection-error.js +17 -0
  13. package/dist/errors/database-connection-error.js.map +1 -0
  14. package/dist/errors/index.d.ts +6 -0
  15. package/dist/errors/index.d.ts.map +1 -0
  16. package/dist/errors/index.js +22 -0
  17. package/dist/errors/index.js.map +1 -0
  18. package/dist/errors/not-authorized-error.d.ts +9 -0
  19. package/dist/errors/not-authorized-error.d.ts.map +1 -0
  20. package/dist/errors/not-authorized-error.js +16 -0
  21. package/dist/errors/not-authorized-error.js.map +1 -0
  22. package/dist/errors/not-found-error.d.ts +9 -0
  23. package/dist/errors/not-found-error.d.ts.map +1 -0
  24. package/dist/errors/not-found-error.js +16 -0
  25. package/dist/errors/not-found-error.js.map +1 -0
  26. package/dist/index.d.ts +5 -0
  27. package/dist/index.d.ts.map +1 -0
  28. package/dist/index.js +21 -0
  29. package/dist/index.js.map +1 -0
  30. package/dist/jwt/index.d.ts +2 -0
  31. package/dist/jwt/index.d.ts.map +1 -0
  32. package/dist/jwt/index.js +18 -0
  33. package/dist/jwt/index.js.map +1 -0
  34. package/dist/jwt/verify.d.ts +18 -0
  35. package/dist/jwt/verify.d.ts.map +1 -0
  36. package/dist/jwt/verify.js +38 -0
  37. package/dist/jwt/verify.js.map +1 -0
  38. package/dist/middleware/authenticate.d.ts +52 -0
  39. package/dist/middleware/authenticate.d.ts.map +1 -0
  40. package/dist/middleware/authenticate.js +95 -0
  41. package/dist/middleware/authenticate.js.map +1 -0
  42. package/dist/middleware/index.d.ts +3 -0
  43. package/dist/middleware/index.d.ts.map +1 -0
  44. package/dist/middleware/index.js +19 -0
  45. package/dist/middleware/index.js.map +1 -0
  46. package/dist/middleware/request-context.d.ts +15 -0
  47. package/dist/middleware/request-context.d.ts.map +1 -0
  48. package/dist/middleware/request-context.js +19 -0
  49. package/dist/middleware/request-context.js.map +1 -0
  50. package/dist/types/jwt.d.ts +33 -0
  51. package/dist/types/jwt.d.ts.map +1 -0
  52. package/dist/types/jwt.js +3 -0
  53. package/dist/types/jwt.js.map +1 -0
  54. package/package.json +56 -0
package/README.md ADDED
@@ -0,0 +1,100 @@
1
+ # @easyweb/authentication
2
+
3
+ Shared authentication primitives for Easyweb microservices — stateless JWT middleware,
4
+ request-context middleware, and the HTTP error classes every service throws.
5
+
6
+ Companion to [`@easyweb/rabbitmq-utils`](https://www.npmjs.com/package/@easyweb/rabbitmq-utils),
7
+ which covers events and observability.
8
+
9
+ ## Install
10
+
11
+ ```bash
12
+ npm install @easyweb/authentication
13
+ ```
14
+
15
+ `express@^5` and `jsonwebtoken@^9` are peer dependencies — the consuming service
16
+ provides them.
17
+
18
+ ## Usage
19
+
20
+ Nothing in this package reads `process.env`. Config is bound once at startup, so the
21
+ package never has to reach into a service's `config` module.
22
+
23
+ ```ts
24
+ import express from "express";
25
+ import cookieParser from "cookie-parser";
26
+ import {
27
+ createAuthMiddleware,
28
+ requestContext,
29
+ NotAuthorizedError,
30
+ } from "@easyweb/authentication";
31
+ import config from "./config";
32
+
33
+ const app = express();
34
+ app.use(cookieParser()); // required: the middleware reads the accessToken cookie
35
+ app.use(requestContext);
36
+
37
+ const authMiddleware = createAuthMiddleware(config.jwt);
38
+ // config.jwt must supply { secret, issuer, audience } matching auth-service's
39
+
40
+ app.get("/me", authMiddleware.authenticate, (req, res) => {
41
+ res.json(req.user); // { id, email, username, roles, permissions }
42
+ });
43
+
44
+ app.get("/feed", authMiddleware.optionalAuth, (req, res) => {
45
+ res.json({ personalised: Boolean(req.user) });
46
+ });
47
+
48
+ app.delete(
49
+ "/admin/:id",
50
+ authMiddleware.authenticate,
51
+ authMiddleware.authorize(["admin"]),
52
+ handler,
53
+ );
54
+ ```
55
+
56
+ Minting tokens (auth-service only):
57
+
58
+ ```ts
59
+ import { createJwtSigner } from "@easyweb/authentication";
60
+
61
+ const signAccessToken = createJwtSigner(config.jwt);
62
+ // config.jwt additionally needs accessTokenTtlSeconds
63
+ ```
64
+
65
+ ## What it verifies — and what it does not
66
+
67
+ `authenticate` is **stateless**. It checks the signature, issuer, audience, expiry, and
68
+ that the payload is a well-formed access token. It performs no database lookup.
69
+
70
+ A logout or session revoke in auth-service stays invisible here until the access token
71
+ expires (`JWT_ACCESS_TOKEN_TTL_SECONDS`, currently 300). If a service needs immediate
72
+ revocation, it must keep its own DB-backed middleware — auth-service does exactly that.
73
+
74
+ `req.user.permissions` is always `[]`. The access token carries no `permissions` claim;
75
+ auth-service resolves those from its own tables at request time. Guarding on this array
76
+ would deny every request.
77
+
78
+ ## Exports
79
+
80
+ | Export | Purpose |
81
+ |---|---|
82
+ | `createAuthMiddleware(config)` | `{ authenticate, optionalAuth, authorize }` |
83
+ | `requestContext` | propagates / generates `x-request-id` |
84
+ | `createJwtVerifier(config)` | `(token) => JwtAccessPayload`, throws on invalid |
85
+ | `createJwtSigner(config)` | `(claims) => string` |
86
+ | `CustomError`, `BadRequestError`, `NotAuthorizedError`, `NotFoundError`, `DatabaseConnectionError` | shared error hierarchy |
87
+ | `JwtAccessPayload`, `JwtAccessClaims`, `JwtVerifyConfig`, `JwtSignConfig` | types |
88
+
89
+ Importing the package also augments `Express.Request` with `user`, `auth`, and
90
+ `requestId`. Remove any local copy of that `declare global` block or TypeScript will
91
+ report duplicate members.
92
+
93
+ ## Token contract
94
+
95
+ `JwtAccessPayload` is the only shape the services agree on. Changing it breaks every
96
+ consumer — bump the major version.
97
+
98
+ ## License
99
+
100
+ MIT
@@ -0,0 +1,10 @@
1
+ import { CustomError } from "./custom-error";
2
+ declare class BadRequestError extends CustomError {
3
+ statusCode: number;
4
+ constructor(message: string);
5
+ serializeErrors(): {
6
+ message: string;
7
+ }[];
8
+ }
9
+ export { BadRequestError };
10
+ //# sourceMappingURL=bad-request-error.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"bad-request-error.d.ts","sourceRoot":"","sources":["../../src/errors/bad-request-error.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,WAAW,EAAE,MAAM,gBAAgB,CAAC;AAE7C,cAAM,eAAgB,SAAQ,WAAW;IACvC,UAAU,SAAO;gBAEL,OAAO,EAAE,MAAM;IAK3B,eAAe;;;CAGhB;AAED,OAAO,EAAE,eAAe,EAAE,CAAC"}
@@ -0,0 +1,16 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.BadRequestError = void 0;
4
+ const custom_error_1 = require("./custom-error");
5
+ class BadRequestError extends custom_error_1.CustomError {
6
+ constructor(message) {
7
+ super(message);
8
+ this.statusCode = 400;
9
+ Object.setPrototypeOf(this, BadRequestError.prototype);
10
+ }
11
+ serializeErrors() {
12
+ return [{ message: this.message }];
13
+ }
14
+ }
15
+ exports.BadRequestError = BadRequestError;
16
+ //# sourceMappingURL=bad-request-error.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"bad-request-error.js","sourceRoot":"","sources":["../../src/errors/bad-request-error.ts"],"names":[],"mappings":";;;AAAA,iDAA6C;AAE7C,MAAM,eAAgB,SAAQ,0BAAW;IAGvC,YAAY,OAAe;QACzB,KAAK,CAAC,OAAO,CAAC,CAAC;QAHjB,eAAU,GAAG,GAAG,CAAC;QAIf,MAAM,CAAC,cAAc,CAAC,IAAI,EAAE,eAAe,CAAC,SAAS,CAAC,CAAC;IACzD,CAAC;IAED,eAAe;QACb,OAAO,CAAC,EAAE,OAAO,EAAE,IAAI,CAAC,OAAO,EAAE,CAAC,CAAC;IACrC,CAAC;CACF;AAEQ,0CAAe"}
@@ -0,0 +1,9 @@
1
+ export declare abstract class CustomError extends Error {
2
+ abstract statusCode: number;
3
+ constructor(message: string);
4
+ abstract serializeErrors(): {
5
+ message: string;
6
+ field?: string;
7
+ }[];
8
+ }
9
+ //# sourceMappingURL=custom-error.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"custom-error.d.ts","sourceRoot":"","sources":["../../src/errors/custom-error.ts"],"names":[],"mappings":"AAAA,8BAAsB,WAAY,SAAQ,KAAK;IAC7C,QAAQ,CAAC,UAAU,EAAE,MAAM,CAAC;gBAEhB,OAAO,EAAE,MAAM;IAK3B,QAAQ,CAAC,eAAe,IAAI;QAAE,OAAO,EAAE,MAAM,CAAC;QAAC,KAAK,CAAC,EAAE,MAAM,CAAA;KAAE,EAAE;CAClE"}
@@ -0,0 +1,11 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.CustomError = void 0;
4
+ class CustomError extends Error {
5
+ constructor(message) {
6
+ super(message);
7
+ Object.setPrototypeOf(this, CustomError.prototype);
8
+ }
9
+ }
10
+ exports.CustomError = CustomError;
11
+ //# sourceMappingURL=custom-error.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"custom-error.js","sourceRoot":"","sources":["../../src/errors/custom-error.ts"],"names":[],"mappings":";;;AAAA,MAAsB,WAAY,SAAQ,KAAK;IAG7C,YAAY,OAAe;QACzB,KAAK,CAAC,OAAO,CAAC,CAAC;QACf,MAAM,CAAC,cAAc,CAAC,IAAI,EAAE,WAAW,CAAC,SAAS,CAAC,CAAC;IACrD,CAAC;CAGF;AATD,kCASC"}
@@ -0,0 +1,10 @@
1
+ import { CustomError } from "./custom-error";
2
+ export declare class DatabaseConnectionError extends CustomError {
3
+ statusCode: number;
4
+ reason: string;
5
+ constructor();
6
+ serializeErrors(): {
7
+ message: string;
8
+ }[];
9
+ }
10
+ //# sourceMappingURL=database-connection-error.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"database-connection-error.d.ts","sourceRoot":"","sources":["../../src/errors/database-connection-error.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,WAAW,EAAE,MAAM,gBAAgB,CAAC;AAE7C,qBAAa,uBAAwB,SAAQ,WAAW;IACtD,UAAU,SAAO;IACjB,MAAM,SAAkC;;IAQxC,eAAe;;;CAGhB"}
@@ -0,0 +1,17 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.DatabaseConnectionError = void 0;
4
+ const custom_error_1 = require("./custom-error");
5
+ class DatabaseConnectionError extends custom_error_1.CustomError {
6
+ constructor() {
7
+ super("Error connecting to database");
8
+ this.statusCode = 500;
9
+ this.reason = "Error connecting to database";
10
+ Object.setPrototypeOf(this, DatabaseConnectionError.prototype);
11
+ }
12
+ serializeErrors() {
13
+ return [{ message: this.reason }];
14
+ }
15
+ }
16
+ exports.DatabaseConnectionError = DatabaseConnectionError;
17
+ //# sourceMappingURL=database-connection-error.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"database-connection-error.js","sourceRoot":"","sources":["../../src/errors/database-connection-error.ts"],"names":[],"mappings":";;;AAAA,iDAA6C;AAE7C,MAAa,uBAAwB,SAAQ,0BAAW;IAItD;QACE,KAAK,CAAC,8BAA8B,CAAC,CAAC;QAJxC,eAAU,GAAG,GAAG,CAAC;QACjB,WAAM,GAAG,8BAA8B,CAAC;QAKtC,MAAM,CAAC,cAAc,CAAC,IAAI,EAAE,uBAAuB,CAAC,SAAS,CAAC,CAAC;IACjE,CAAC;IAED,eAAe;QACb,OAAO,CAAC,EAAE,OAAO,EAAE,IAAI,CAAC,MAAM,EAAE,CAAC,CAAC;IACpC,CAAC;CACF;AAbD,0DAaC"}
@@ -0,0 +1,6 @@
1
+ export * from "./custom-error";
2
+ export * from "./bad-request-error";
3
+ export * from "./not-authorized-error";
4
+ export * from "./not-found-error";
5
+ export * from "./database-connection-error";
6
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/errors/index.ts"],"names":[],"mappings":"AAAA,cAAc,gBAAgB,CAAC;AAC/B,cAAc,qBAAqB,CAAC;AACpC,cAAc,wBAAwB,CAAC;AACvC,cAAc,mBAAmB,CAAC;AAClC,cAAc,6BAA6B,CAAC"}
@@ -0,0 +1,22 @@
1
+ "use strict";
2
+ var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
3
+ if (k2 === undefined) k2 = k;
4
+ var desc = Object.getOwnPropertyDescriptor(m, k);
5
+ if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
6
+ desc = { enumerable: true, get: function() { return m[k]; } };
7
+ }
8
+ Object.defineProperty(o, k2, desc);
9
+ }) : (function(o, m, k, k2) {
10
+ if (k2 === undefined) k2 = k;
11
+ o[k2] = m[k];
12
+ }));
13
+ var __exportStar = (this && this.__exportStar) || function(m, exports) {
14
+ for (var p in m) if (p !== "default" && !Object.prototype.hasOwnProperty.call(exports, p)) __createBinding(exports, m, p);
15
+ };
16
+ Object.defineProperty(exports, "__esModule", { value: true });
17
+ __exportStar(require("./custom-error"), exports);
18
+ __exportStar(require("./bad-request-error"), exports);
19
+ __exportStar(require("./not-authorized-error"), exports);
20
+ __exportStar(require("./not-found-error"), exports);
21
+ __exportStar(require("./database-connection-error"), exports);
22
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/errors/index.ts"],"names":[],"mappings":";;;;;;;;;;;;;;;;AAAA,iDAA+B;AAC/B,sDAAoC;AACpC,yDAAuC;AACvC,oDAAkC;AAClC,8DAA4C"}
@@ -0,0 +1,9 @@
1
+ import { CustomError } from "./custom-error";
2
+ export declare class NotAuthorizedError extends CustomError {
3
+ statusCode: number;
4
+ constructor(message?: string);
5
+ serializeErrors(): {
6
+ message: string;
7
+ }[];
8
+ }
9
+ //# sourceMappingURL=not-authorized-error.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"not-authorized-error.d.ts","sourceRoot":"","sources":["../../src/errors/not-authorized-error.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,WAAW,EAAE,MAAM,gBAAgB,CAAC;AAE7C,qBAAa,kBAAmB,SAAQ,WAAW;IACjD,UAAU,SAAO;gBAEL,OAAO,GAAE,MAAyB;IAK9C,eAAe;;;CAGhB"}
@@ -0,0 +1,16 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.NotAuthorizedError = void 0;
4
+ const custom_error_1 = require("./custom-error");
5
+ class NotAuthorizedError extends custom_error_1.CustomError {
6
+ constructor(message = "Not authorized") {
7
+ super(message);
8
+ this.statusCode = 401;
9
+ Object.setPrototypeOf(this, NotAuthorizedError.prototype);
10
+ }
11
+ serializeErrors() {
12
+ return [{ message: this.message }];
13
+ }
14
+ }
15
+ exports.NotAuthorizedError = NotAuthorizedError;
16
+ //# sourceMappingURL=not-authorized-error.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"not-authorized-error.js","sourceRoot":"","sources":["../../src/errors/not-authorized-error.ts"],"names":[],"mappings":";;;AAAA,iDAA6C;AAE7C,MAAa,kBAAmB,SAAQ,0BAAW;IAGjD,YAAY,UAAkB,gBAAgB;QAC5C,KAAK,CAAC,OAAO,CAAC,CAAC;QAHjB,eAAU,GAAG,GAAG,CAAC;QAIf,MAAM,CAAC,cAAc,CAAC,IAAI,EAAE,kBAAkB,CAAC,SAAS,CAAC,CAAC;IAC5D,CAAC;IAED,eAAe;QACb,OAAO,CAAC,EAAE,OAAO,EAAE,IAAI,CAAC,OAAO,EAAE,CAAC,CAAC;IACrC,CAAC;CACF;AAXD,gDAWC"}
@@ -0,0 +1,9 @@
1
+ import { CustomError } from "./custom-error";
2
+ export declare class NotFoundError extends CustomError {
3
+ statusCode: number;
4
+ constructor();
5
+ serializeErrors(): {
6
+ message: string;
7
+ }[];
8
+ }
9
+ //# sourceMappingURL=not-found-error.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"not-found-error.d.ts","sourceRoot":"","sources":["../../src/errors/not-found-error.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,WAAW,EAAE,MAAM,gBAAgB,CAAC;AAE7C,qBAAa,aAAc,SAAQ,WAAW;IAC5C,UAAU,SAAO;;IAOjB,eAAe;;;CAGhB"}
@@ -0,0 +1,16 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.NotFoundError = void 0;
4
+ const custom_error_1 = require("./custom-error");
5
+ class NotFoundError extends custom_error_1.CustomError {
6
+ constructor() {
7
+ super("Route not found");
8
+ this.statusCode = 404;
9
+ Object.setPrototypeOf(this, NotFoundError.prototype);
10
+ }
11
+ serializeErrors() {
12
+ return [{ message: "Not Found" }];
13
+ }
14
+ }
15
+ exports.NotFoundError = NotFoundError;
16
+ //# sourceMappingURL=not-found-error.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"not-found-error.js","sourceRoot":"","sources":["../../src/errors/not-found-error.ts"],"names":[],"mappings":";;;AAAA,iDAA6C;AAE7C,MAAa,aAAc,SAAQ,0BAAW;IAG5C;QACE,KAAK,CAAC,iBAAiB,CAAC,CAAC;QAH3B,eAAU,GAAG,GAAG,CAAC;QAIf,MAAM,CAAC,cAAc,CAAC,IAAI,EAAE,aAAa,CAAC,SAAS,CAAC,CAAC;IACvD,CAAC;IAED,eAAe;QACb,OAAO,CAAC,EAAE,OAAO,EAAE,WAAW,EAAE,CAAC,CAAC;IACpC,CAAC;CACF;AAXD,sCAWC"}
@@ -0,0 +1,5 @@
1
+ export * from "./errors";
2
+ export * from "./jwt";
3
+ export * from "./middleware";
4
+ export * from "./types/jwt";
5
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,cAAc,UAAU,CAAC;AACzB,cAAc,OAAO,CAAC;AACtB,cAAc,cAAc,CAAC;AAC7B,cAAc,aAAa,CAAC"}
package/dist/index.js ADDED
@@ -0,0 +1,21 @@
1
+ "use strict";
2
+ var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
3
+ if (k2 === undefined) k2 = k;
4
+ var desc = Object.getOwnPropertyDescriptor(m, k);
5
+ if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
6
+ desc = { enumerable: true, get: function() { return m[k]; } };
7
+ }
8
+ Object.defineProperty(o, k2, desc);
9
+ }) : (function(o, m, k, k2) {
10
+ if (k2 === undefined) k2 = k;
11
+ o[k2] = m[k];
12
+ }));
13
+ var __exportStar = (this && this.__exportStar) || function(m, exports) {
14
+ for (var p in m) if (p !== "default" && !Object.prototype.hasOwnProperty.call(exports, p)) __createBinding(exports, m, p);
15
+ };
16
+ Object.defineProperty(exports, "__esModule", { value: true });
17
+ __exportStar(require("./errors"), exports);
18
+ __exportStar(require("./jwt"), exports);
19
+ __exportStar(require("./middleware"), exports);
20
+ __exportStar(require("./types/jwt"), exports);
21
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":";;;;;;;;;;;;;;;;AAAA,2CAAyB;AACzB,wCAAsB;AACtB,+CAA6B;AAC7B,8CAA4B"}
@@ -0,0 +1,2 @@
1
+ export * from "./verify";
2
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/jwt/index.ts"],"names":[],"mappings":"AAAA,cAAc,UAAU,CAAC"}
@@ -0,0 +1,18 @@
1
+ "use strict";
2
+ var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
3
+ if (k2 === undefined) k2 = k;
4
+ var desc = Object.getOwnPropertyDescriptor(m, k);
5
+ if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
6
+ desc = { enumerable: true, get: function() { return m[k]; } };
7
+ }
8
+ Object.defineProperty(o, k2, desc);
9
+ }) : (function(o, m, k, k2) {
10
+ if (k2 === undefined) k2 = k;
11
+ o[k2] = m[k];
12
+ }));
13
+ var __exportStar = (this && this.__exportStar) || function(m, exports) {
14
+ for (var p in m) if (p !== "default" && !Object.prototype.hasOwnProperty.call(exports, p)) __createBinding(exports, m, p);
15
+ };
16
+ Object.defineProperty(exports, "__esModule", { value: true });
17
+ __exportStar(require("./verify"), exports);
18
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/jwt/index.ts"],"names":[],"mappings":";;;;;;;;;;;;;;;;AAAA,2CAAyB"}
@@ -0,0 +1,18 @@
1
+ import type { JwtAccessClaims, JwtAccessPayload, JwtSignConfig, JwtVerifyConfig } from "../types/jwt";
2
+ /**
3
+ * Factory rather than a bare function: package code cannot reach a service's
4
+ * `config` module, so the secret/issuer/audience are bound once at startup.
5
+ *
6
+ * The returned verifier throws whatever `jsonwebtoken` throws
7
+ * (`JsonWebTokenError`, `TokenExpiredError`); callers translate that into
8
+ * `NotAuthorizedError`.
9
+ */
10
+ export declare function createJwtVerifier(config: JwtVerifyConfig): (token: string) => JwtAccessPayload;
11
+ /**
12
+ * Only auth-service mints tokens. Every other service consumes them and needs
13
+ * `createJwtVerifier` alone.
14
+ */
15
+ export declare function createJwtSigner(config: JwtSignConfig): (payload: JwtAccessClaims) => string;
16
+ export type JwtVerifier = ReturnType<typeof createJwtVerifier>;
17
+ export type JwtSigner = ReturnType<typeof createJwtSigner>;
18
+ //# sourceMappingURL=verify.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"verify.d.ts","sourceRoot":"","sources":["../../src/jwt/verify.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EACV,eAAe,EACf,gBAAgB,EAChB,aAAa,EACb,eAAe,EAChB,MAAM,cAAc,CAAC;AAEtB;;;;;;;GAOG;AACH,wBAAgB,iBAAiB,CAAC,MAAM,EAAE,eAAe,IACrB,OAAO,MAAM,KAAG,gBAAgB,CAMnE;AAED;;;GAGG;AACH,wBAAgB,eAAe,CAAC,MAAM,EAAE,aAAa,IACnB,SAAS,eAAe,KAAG,MAAM,CAOlE;AAED,MAAM,MAAM,WAAW,GAAG,UAAU,CAAC,OAAO,iBAAiB,CAAC,CAAC;AAC/D,MAAM,MAAM,SAAS,GAAG,UAAU,CAAC,OAAO,eAAe,CAAC,CAAC"}
@@ -0,0 +1,38 @@
1
+ "use strict";
2
+ var __importDefault = (this && this.__importDefault) || function (mod) {
3
+ return (mod && mod.__esModule) ? mod : { "default": mod };
4
+ };
5
+ Object.defineProperty(exports, "__esModule", { value: true });
6
+ exports.createJwtVerifier = createJwtVerifier;
7
+ exports.createJwtSigner = createJwtSigner;
8
+ const jsonwebtoken_1 = __importDefault(require("jsonwebtoken"));
9
+ /**
10
+ * Factory rather than a bare function: package code cannot reach a service's
11
+ * `config` module, so the secret/issuer/audience are bound once at startup.
12
+ *
13
+ * The returned verifier throws whatever `jsonwebtoken` throws
14
+ * (`JsonWebTokenError`, `TokenExpiredError`); callers translate that into
15
+ * `NotAuthorizedError`.
16
+ */
17
+ function createJwtVerifier(config) {
18
+ return function verifyAccessToken(token) {
19
+ return jsonwebtoken_1.default.verify(token, config.secret, {
20
+ issuer: config.issuer,
21
+ audience: config.audience,
22
+ });
23
+ };
24
+ }
25
+ /**
26
+ * Only auth-service mints tokens. Every other service consumes them and needs
27
+ * `createJwtVerifier` alone.
28
+ */
29
+ function createJwtSigner(config) {
30
+ return function signAccessToken(payload) {
31
+ return jsonwebtoken_1.default.sign(payload, config.secret, {
32
+ expiresIn: config.accessTokenTtlSeconds,
33
+ issuer: config.issuer,
34
+ audience: config.audience,
35
+ });
36
+ };
37
+ }
38
+ //# sourceMappingURL=verify.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"verify.js","sourceRoot":"","sources":["../../src/jwt/verify.ts"],"names":[],"mappings":";;;;;AAgBA,8CAOC;AAMD,0CAQC;AArCD,gEAA+B;AAQ/B;;;;;;;GAOG;AACH,SAAgB,iBAAiB,CAAC,MAAuB;IACvD,OAAO,SAAS,iBAAiB,CAAC,KAAa;QAC7C,OAAO,sBAAG,CAAC,MAAM,CAAC,KAAK,EAAE,MAAM,CAAC,MAAM,EAAE;YACtC,MAAM,EAAE,MAAM,CAAC,MAAM;YACrB,QAAQ,EAAE,MAAM,CAAC,QAAQ;SAC1B,CAAqB,CAAC;IACzB,CAAC,CAAC;AACJ,CAAC;AAED;;;GAGG;AACH,SAAgB,eAAe,CAAC,MAAqB;IACnD,OAAO,SAAS,eAAe,CAAC,OAAwB;QACtD,OAAO,sBAAG,CAAC,IAAI,CAAC,OAAO,EAAE,MAAM,CAAC,MAAM,EAAE;YACtC,SAAS,EAAE,MAAM,CAAC,qBAAqB;YACvC,MAAM,EAAE,MAAM,CAAC,MAAM;YACrB,QAAQ,EAAE,MAAM,CAAC,QAAQ;SACP,CAAC,CAAC;IACxB,CAAC,CAAC;AACJ,CAAC"}
@@ -0,0 +1,52 @@
1
+ import type { NextFunction, Request, Response } from "express";
2
+ import type { JwtVerifyConfig } from "../types/jwt";
3
+ /**
4
+ * Stateless verification. Unlike auth-service's own middleware there is no
5
+ * database round trip: the access token is verified against the shared secret
6
+ * and its claims are trusted as-is.
7
+ *
8
+ * TRADE-OFF — a logout or session revoke performed in auth-service is invisible
9
+ * here until the access token expires (JWT_ACCESS_TOKEN_TTL_SECONDS, currently
10
+ * 300). That window is accepted for now. The upgrade path is a shared Redis
11
+ * denylist checked after verification:
12
+ *
13
+ * if (await redis.get(`session:revoked:${decoded.sessionId}`)) throw ...
14
+ *
15
+ * which requires auth-service to start publishing those keys on logout/revoke.
16
+ * It does not today.
17
+ *
18
+ * Any service needing immediate revocation must keep its own DB-backed
19
+ * middleware instead of this one.
20
+ */
21
+ declare global {
22
+ namespace Express {
23
+ interface Request {
24
+ user?: {
25
+ id: string;
26
+ email: string;
27
+ username: string | null;
28
+ roles: string[];
29
+ permissions: string[];
30
+ };
31
+ auth?: {
32
+ userId: string;
33
+ sessionId?: string;
34
+ };
35
+ }
36
+ }
37
+ }
38
+ export type AuthMiddleware = {
39
+ /** Rejects with 401 unless the request carries a valid access token. */
40
+ authenticate: (req: Request, res: Response, next: NextFunction) => void;
41
+ /** Populates `req.user` when a valid token is present; never rejects. */
42
+ optionalAuth: (req: Request, res: Response, next: NextFunction) => void;
43
+ /** Role guard. Use after `authenticate`. */
44
+ authorize: (allowedRoles: string[]) => (req: Request, res: Response, next: NextFunction) => void;
45
+ };
46
+ /**
47
+ * Binds the JWT config once at startup and returns the middleware trio. The
48
+ * grouped return keeps call sites reading as `authMiddleware.authenticate`,
49
+ * matching auth-service's class-based middleware.
50
+ */
51
+ export declare function createAuthMiddleware(config: JwtVerifyConfig): AuthMiddleware;
52
+ //# sourceMappingURL=authenticate.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"authenticate.d.ts","sourceRoot":"","sources":["../../src/middleware/authenticate.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,YAAY,EAAE,OAAO,EAAE,QAAQ,EAAE,MAAM,SAAS,CAAC;AAG/D,OAAO,KAAK,EAAoB,eAAe,EAAE,MAAM,cAAc,CAAC;AAEtE;;;;;;;;;;;;;;;;;GAiBG;AAGH,OAAO,CAAC,MAAM,CAAC;IACb,UAAU,OAAO,CAAC;QAChB,UAAU,OAAO;YACf,IAAI,CAAC,EAAE;gBACL,EAAE,EAAE,MAAM,CAAC;gBACX,KAAK,EAAE,MAAM,CAAC;gBACd,QAAQ,EAAE,MAAM,GAAG,IAAI,CAAC;gBACxB,KAAK,EAAE,MAAM,EAAE,CAAC;gBAChB,WAAW,EAAE,MAAM,EAAE,CAAC;aACvB,CAAC;YACF,IAAI,CAAC,EAAE;gBACL,MAAM,EAAE,MAAM,CAAC;gBACf,SAAS,CAAC,EAAE,MAAM,CAAC;aACpB,CAAC;SACH;KACF;CACF;AAoCD,MAAM,MAAM,cAAc,GAAG;IAC3B,wEAAwE;IACxE,YAAY,EAAE,CAAC,GAAG,EAAE,OAAO,EAAE,GAAG,EAAE,QAAQ,EAAE,IAAI,EAAE,YAAY,KAAK,IAAI,CAAC;IACxE,yEAAyE;IACzE,YAAY,EAAE,CAAC,GAAG,EAAE,OAAO,EAAE,GAAG,EAAE,QAAQ,EAAE,IAAI,EAAE,YAAY,KAAK,IAAI,CAAC;IACxE,4CAA4C;IAC5C,SAAS,EAAE,CACT,YAAY,EAAE,MAAM,EAAE,KACnB,CAAC,GAAG,EAAE,OAAO,EAAE,GAAG,EAAE,QAAQ,EAAE,IAAI,EAAE,YAAY,KAAK,IAAI,CAAC;CAChE,CAAC;AAEF;;;;GAIG;AACH,wBAAgB,oBAAoB,CAAC,MAAM,EAAE,eAAe,GAAG,cAAc,CAgF5E"}
@@ -0,0 +1,95 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.createAuthMiddleware = createAuthMiddleware;
4
+ const verify_1 = require("../jwt/verify");
5
+ const not_authorized_error_1 = require("../errors/not-authorized-error");
6
+ /** Bearer header first, then the `accessToken` cookie auth-service sets. */
7
+ function extractToken(req) {
8
+ const authHeader = req.headers.authorization;
9
+ if (authHeader && authHeader.startsWith("Bearer ")) {
10
+ return authHeader.substring(7);
11
+ }
12
+ if (req.cookies && req.cookies.accessToken) {
13
+ return req.cookies.accessToken;
14
+ }
15
+ return null;
16
+ }
17
+ function attachClaims(req, decoded) {
18
+ req.user = {
19
+ id: decoded.sub,
20
+ email: decoded.email,
21
+ username: decoded.username ?? null,
22
+ roles: decoded.roles ?? [],
23
+ // The access token carries no `permissions` claim — auth-service resolves
24
+ // those from its own tables. Anything needing permission-level checks must
25
+ // either get the claim added upstream or query auth-service directly;
26
+ // guarding on this empty array would deny every request.
27
+ permissions: [],
28
+ };
29
+ req.auth = {
30
+ userId: decoded.sub,
31
+ sessionId: decoded.sessionId,
32
+ };
33
+ }
34
+ /**
35
+ * Binds the JWT config once at startup and returns the middleware trio. The
36
+ * grouped return keeps call sites reading as `authMiddleware.authenticate`,
37
+ * matching auth-service's class-based middleware.
38
+ */
39
+ function createAuthMiddleware(config) {
40
+ const verifyAccessToken = (0, verify_1.createJwtVerifier)(config);
41
+ /**
42
+ * Verifies the token and returns its claims, or null when anything about it
43
+ * is wrong — bad signature, wrong issuer/audience, expired, or a payload that
44
+ * is not a well-formed access token.
45
+ */
46
+ function decodeAccessToken(token) {
47
+ let decoded;
48
+ try {
49
+ decoded = verifyAccessToken(token);
50
+ }
51
+ catch {
52
+ return null;
53
+ }
54
+ if (!decoded ||
55
+ decoded.type !== "access" ||
56
+ !decoded.sub ||
57
+ !decoded.sessionId ||
58
+ !decoded.iat) {
59
+ return null;
60
+ }
61
+ return decoded;
62
+ }
63
+ const authenticate = (req, _res, next) => {
64
+ const token = extractToken(req);
65
+ if (!token) {
66
+ throw new not_authorized_error_1.NotAuthorizedError();
67
+ }
68
+ const decoded = decodeAccessToken(token);
69
+ if (!decoded) {
70
+ throw new not_authorized_error_1.NotAuthorizedError();
71
+ }
72
+ attachClaims(req, decoded);
73
+ next();
74
+ };
75
+ const optionalAuth = (req, _res, next) => {
76
+ const token = extractToken(req);
77
+ if (token) {
78
+ const decoded = decodeAccessToken(token);
79
+ if (decoded)
80
+ attachClaims(req, decoded);
81
+ }
82
+ next();
83
+ };
84
+ const authorize = (allowedRoles) => {
85
+ return (req, _res, next) => {
86
+ const roles = req.user?.roles ?? [];
87
+ if (!roles.some((r) => allowedRoles.includes(r))) {
88
+ throw new not_authorized_error_1.NotAuthorizedError("Insufficient role");
89
+ }
90
+ next();
91
+ };
92
+ };
93
+ return { authenticate, optionalAuth, authorize };
94
+ }
95
+ //# sourceMappingURL=authenticate.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"authenticate.js","sourceRoot":"","sources":["../../src/middleware/authenticate.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,3 @@
1
+ export * from "./authenticate";
2
+ export * from "./request-context";
3
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/middleware/index.ts"],"names":[],"mappings":"AAAA,cAAc,gBAAgB,CAAC;AAC/B,cAAc,mBAAmB,CAAC"}
@@ -0,0 +1,19 @@
1
+ "use strict";
2
+ var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
3
+ if (k2 === undefined) k2 = k;
4
+ var desc = Object.getOwnPropertyDescriptor(m, k);
5
+ if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
6
+ desc = { enumerable: true, get: function() { return m[k]; } };
7
+ }
8
+ Object.defineProperty(o, k2, desc);
9
+ }) : (function(o, m, k, k2) {
10
+ if (k2 === undefined) k2 = k;
11
+ o[k2] = m[k];
12
+ }));
13
+ var __exportStar = (this && this.__exportStar) || function(m, exports) {
14
+ for (var p in m) if (p !== "default" && !Object.prototype.hasOwnProperty.call(exports, p)) __createBinding(exports, m, p);
15
+ };
16
+ Object.defineProperty(exports, "__esModule", { value: true });
17
+ __exportStar(require("./authenticate"), exports);
18
+ __exportStar(require("./request-context"), exports);
19
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/middleware/index.ts"],"names":[],"mappings":";;;;;;;;;;;;;;;;AAAA,iDAA+B;AAC/B,oDAAkC"}
@@ -0,0 +1,15 @@
1
+ import type { Request, Response, NextFunction } from "express";
2
+ declare global {
3
+ namespace Express {
4
+ interface Request {
5
+ requestId: string;
6
+ }
7
+ }
8
+ }
9
+ /**
10
+ * Picks up x-request-id from incoming headers (for inter-service forwarding),
11
+ * or generates a new UUID when the request originates externally.
12
+ * Always echoes the final value back in the response header.
13
+ */
14
+ export declare function requestContext(req: Request, res: Response, next: NextFunction): void;
15
+ //# sourceMappingURL=request-context.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"request-context.d.ts","sourceRoot":"","sources":["../../src/middleware/request-context.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,OAAO,EAAE,QAAQ,EAAE,YAAY,EAAE,MAAM,SAAS,CAAC;AAG/D,OAAO,CAAC,MAAM,CAAC;IACb,UAAU,OAAO,CAAC;QAChB,UAAU,OAAO;YACf,SAAS,EAAE,MAAM,CAAC;SACnB;KACF;CACF;AAED;;;;GAIG;AACH,wBAAgB,cAAc,CAC5B,GAAG,EAAE,OAAO,EACZ,GAAG,EAAE,QAAQ,EACb,IAAI,EAAE,YAAY,QAYnB"}
@@ -0,0 +1,19 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.requestContext = requestContext;
4
+ const crypto_1 = require("crypto");
5
+ /**
6
+ * Picks up x-request-id from incoming headers (for inter-service forwarding),
7
+ * or generates a new UUID when the request originates externally.
8
+ * Always echoes the final value back in the response header.
9
+ */
10
+ function requestContext(req, res, next) {
11
+ const incoming = req.headers["x-request-id"];
12
+ const requestId = typeof incoming === "string" && incoming.length > 0
13
+ ? incoming
14
+ : (0, crypto_1.randomUUID)();
15
+ req.requestId = requestId;
16
+ res.setHeader("x-request-id", requestId);
17
+ next();
18
+ }
19
+ //# sourceMappingURL=request-context.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"request-context.js","sourceRoot":"","sources":["../../src/middleware/request-context.ts"],"names":[],"mappings":";;AAgBA,wCAeC;AA9BD,mCAAoC;AAUpC;;;;GAIG;AACH,SAAgB,cAAc,CAC5B,GAAY,EACZ,GAAa,EACb,IAAkB;IAElB,MAAM,QAAQ,GAAG,GAAG,CAAC,OAAO,CAAC,cAAc,CAAC,CAAC;IAC7C,MAAM,SAAS,GACb,OAAO,QAAQ,KAAK,QAAQ,IAAI,QAAQ,CAAC,MAAM,GAAG,CAAC;QACjD,CAAC,CAAC,QAAQ;QACV,CAAC,CAAC,IAAA,mBAAU,GAAE,CAAC;IAEnB,GAAG,CAAC,SAAS,GAAG,SAAS,CAAC;IAC1B,GAAG,CAAC,SAAS,CAAC,cAAc,EAAE,SAAS,CAAC,CAAC;IAEzC,IAAI,EAAE,CAAC;AACT,CAAC"}
@@ -0,0 +1,33 @@
1
+ /**
2
+ * Claim set minted by auth-service's `signAccessTokenForSession`.
3
+ *
4
+ * This is the only shape the services agree on. Any change here is a breaking
5
+ * change for every consumer — bump the major version.
6
+ *
7
+ * Note there is no `permissions` claim: auth-service resolves permissions from
8
+ * its own tables at request time and does not put them in the token.
9
+ */
10
+ export type JwtAccessPayload = {
11
+ sub: string;
12
+ email: string;
13
+ username: string;
14
+ roles: string[];
15
+ sessionId: string;
16
+ type: "access";
17
+ /** Registered claims stamped by `jsonwebtoken` at sign time. */
18
+ iat?: number;
19
+ exp?: number;
20
+ };
21
+ /** What a caller supplies when minting — the registered claims are added for it. */
22
+ export type JwtAccessClaims = Omit<JwtAccessPayload, "iat" | "exp">;
23
+ /** Everything needed to verify a token. Must match the issuing service's values. */
24
+ export type JwtVerifyConfig = {
25
+ secret: string;
26
+ issuer: string;
27
+ audience: string;
28
+ };
29
+ /** Verification config plus the lifetime applied to newly minted tokens. */
30
+ export type JwtSignConfig = JwtVerifyConfig & {
31
+ accessTokenTtlSeconds: number;
32
+ };
33
+ //# sourceMappingURL=jwt.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"jwt.d.ts","sourceRoot":"","sources":["../../src/types/jwt.ts"],"names":[],"mappings":"AAAA;;;;;;;;GAQG;AACH,MAAM,MAAM,gBAAgB,GAAG;IAC7B,GAAG,EAAE,MAAM,CAAC;IACZ,KAAK,EAAE,MAAM,CAAC;IACd,QAAQ,EAAE,MAAM,CAAC;IACjB,KAAK,EAAE,MAAM,EAAE,CAAC;IAChB,SAAS,EAAE,MAAM,CAAC;IAClB,IAAI,EAAE,QAAQ,CAAC;IACf,gEAAgE;IAChE,GAAG,CAAC,EAAE,MAAM,CAAC;IACb,GAAG,CAAC,EAAE,MAAM,CAAC;CACd,CAAC;AAEF,oFAAoF;AACpF,MAAM,MAAM,eAAe,GAAG,IAAI,CAAC,gBAAgB,EAAE,KAAK,GAAG,KAAK,CAAC,CAAC;AAEpE,oFAAoF;AACpF,MAAM,MAAM,eAAe,GAAG;IAC5B,MAAM,EAAE,MAAM,CAAC;IACf,MAAM,EAAE,MAAM,CAAC;IACf,QAAQ,EAAE,MAAM,CAAC;CAClB,CAAC;AAEF,4EAA4E;AAC5E,MAAM,MAAM,aAAa,GAAG,eAAe,GAAG;IAC5C,qBAAqB,EAAE,MAAM,CAAC;CAC/B,CAAC"}
@@ -0,0 +1,3 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ //# sourceMappingURL=jwt.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"jwt.js","sourceRoot":"","sources":["../../src/types/jwt.ts"],"names":[],"mappings":""}
package/package.json ADDED
@@ -0,0 +1,56 @@
1
+ {
2
+ "name": "@easyweb/authentication",
3
+ "version": "1.0.0",
4
+ "description": "Shared authentication primitives for Easyweb microservices: stateless JWT middleware, request context, and HTTP error classes",
5
+ "main": "dist/index.js",
6
+ "types": "dist/index.d.ts",
7
+ "exports": {
8
+ ".": {
9
+ "require": "./dist/index.js",
10
+ "import": "./dist/index.js",
11
+ "types": "./dist/index.d.ts"
12
+ }
13
+ },
14
+ "files": [
15
+ "dist",
16
+ "README.md"
17
+ ],
18
+ "scripts": {
19
+ "build": "tsc",
20
+ "build:watch": "tsc --watch",
21
+ "prepublishOnly": "npm run build",
22
+ "clean": "rimraf dist"
23
+ },
24
+ "keywords": [
25
+ "microservices",
26
+ "express",
27
+ "middleware",
28
+ "authentication",
29
+ "jwt",
30
+ "error-handling"
31
+ ],
32
+ "author": "Easy Web Team",
33
+ "license": "MIT",
34
+ "repository": {
35
+ "type": "git",
36
+ "url": "https://github.com/Alpine-Solusi/website-builder.git",
37
+ "directory": "common-auth"
38
+ },
39
+ "peerDependencies": {
40
+ "express": "^5.0.0",
41
+ "jsonwebtoken": "^9.0.0"
42
+ },
43
+ "devDependencies": {
44
+ "@types/express": "^5.0.6",
45
+ "@types/jsonwebtoken": "^9.0.10",
46
+ "@types/node": "^26.0.1",
47
+ "rimraf": "^6.1.3",
48
+ "typescript": "^6.0.3"
49
+ },
50
+ "engines": {
51
+ "node": ">=18.0.0"
52
+ },
53
+ "publishConfig": {
54
+ "access": "public"
55
+ }
56
+ }