@discover-cloud/shared 1.2.9 → 1.3.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/authorization/index.d.ts +1 -1
- package/dist/authorization/index.js +1 -1
- package/dist/authorization/permission-cache.service.d.ts +104 -16
- package/dist/authorization/permission-cache.service.js +156 -143
- package/dist/authorization/permission-checker.d.ts +30 -0
- package/dist/authorization/permission-checker.js +40 -0
- package/dist/contracts/auth-service/account.dto.d.ts +30 -0
- package/dist/contracts/auth-service/account.dto.js +7 -0
- package/dist/contracts/auth-service/auth.dto.d.ts +21 -0
- package/dist/contracts/auth-service/auth.dto.js +10 -0
- package/dist/dtos/auth-service.dto.d.ts +72 -26
- package/dist/dtos/auth-service.dto.js +4 -0
- package/dist/dtos/cloud-service.dto.d.ts +51 -27
- package/dist/dtos/cloud-service.dto.js +5 -0
- package/dist/dtos/insights-service.dto.d.ts +18 -27
- package/dist/dtos/insights-service.dto.js +8 -0
- package/dist/dtos/response.dto.d.ts +7 -84
- package/dist/dtos/response.dto.js +2 -21
- package/dist/dtos/user-service.dto.d.ts +118 -13
- package/dist/enums/domain.enums.d.ts +246 -75
- package/dist/enums/domain.enums.js +305 -102
- package/dist/enums/permissions.enums.d.ts +142 -80
- package/dist/enums/permissions.enums.js +174 -133
- package/dist/errors/app-error.d.ts +13 -18
- package/dist/errors/app-error.js +14 -20
- package/dist/errors/http-errors.d.ts +105 -17
- package/dist/errors/http-errors.js +118 -33
- package/dist/http/index.d.ts +1 -0
- package/dist/http/index.js +1 -0
- package/dist/http/request-context.d.ts +8 -0
- package/dist/http/request-context.js +37 -0
- package/dist/http/service-client.d.ts +91 -38
- package/dist/http/service-client.js +102 -53
- package/dist/index.d.ts +1 -0
- package/dist/index.js +1 -0
- package/dist/jwt/index.d.ts +2 -1
- package/dist/jwt/index.js +2 -1
- package/dist/jwt/machine-jwt-verifier.d.ts +21 -0
- package/dist/jwt/machine-jwt-verifier.js +84 -0
- package/dist/jwt/machine-token-client.d.ts +35 -4
- package/dist/jwt/machine-token-client.js +57 -23
- package/dist/jwt/user-jwt-verifier.d.ts +31 -0
- package/dist/jwt/user-jwt-verifier.js +101 -0
- package/dist/messaging/index.d.ts +1 -0
- package/dist/{security → messaging}/index.js +1 -1
- package/dist/messaging/rabbitmq.client.d.ts +13 -0
- package/dist/messaging/rabbitmq.client.js +127 -0
- package/dist/middleware/error-handler.middleware.d.ts +8 -28
- package/dist/middleware/error-handler.middleware.js +61 -52
- package/dist/middleware/index.d.ts +7 -5
- package/dist/middleware/index.js +7 -5
- package/dist/middleware/request-context.middleware.d.ts +17 -0
- package/dist/middleware/request-context.middleware.js +73 -0
- package/dist/middleware/require-auth.middleware.d.ts +17 -70
- package/dist/middleware/require-auth.middleware.js +24 -103
- package/dist/middleware/require-machine.middleware.d.ts +38 -0
- package/dist/middleware/require-machine.middleware.js +123 -0
- package/dist/middleware/require-org-permission-from-body.middleware.d.ts +10 -0
- package/dist/middleware/require-org-permission-from-body.middleware.js +24 -0
- package/dist/middleware/require-org-permission.middleware.d.ts +19 -0
- package/dist/middleware/require-org-permission.middleware.js +115 -0
- package/dist/middleware/require-platform-permission.middleware.d.ts +19 -0
- package/dist/middleware/require-platform-permission.middleware.js +91 -0
- package/dist/middleware/require-user.middleware.d.ts +14 -0
- package/dist/middleware/require-user.middleware.js +30 -0
- package/dist/middleware/require-workspace-permission.middleware.d.ts +20 -0
- package/dist/middleware/require-workspace-permission.middleware.js +114 -0
- package/dist/middleware/validate.middleware.d.ts +29 -29
- package/dist/middleware/validate.middleware.js +30 -32
- package/dist/types/express.types.d.ts +83 -122
- package/dist/types/express.types.js +28 -47
- package/dist/utils/date.util.d.ts +6 -0
- package/dist/utils/date.util.js +11 -0
- package/dist/utils/env.util.d.ts +6 -0
- package/dist/utils/env.util.js +19 -0
- package/dist/utils/index.d.ts +5 -4
- package/dist/utils/index.js +5 -4
- package/dist/utils/logger.util.d.ts +26 -0
- package/dist/utils/logger.util.js +53 -0
- package/dist/utils/pagination.util.d.ts +6 -0
- package/dist/utils/pagination.util.js +20 -0
- package/dist/utils/response.util.d.ts +27 -0
- package/dist/utils/response.util.js +56 -0
- package/dist/utils/slug.util.d.ts +9 -0
- package/dist/utils/slug.util.js +32 -0
- package/dist/utils/url-safety.util.d.ts +6 -0
- package/dist/utils/url-safety.util.js +72 -0
- package/package.json +3 -1
- package/dist/authorization/permissions.d.ts +0 -78
- package/dist/authorization/permissions.js +0 -174
- package/dist/context/access-context.d.ts +0 -10
- package/dist/context/access-context.js +0 -2
- package/dist/context/index.d.ts +0 -1
- package/dist/context/index.js +0 -17
- package/dist/dto/auth-service.dtos.d.ts +0 -44
- package/dist/dto/auth-service.dtos.js +0 -2
- package/dist/dto/index.d.ts +0 -3
- package/dist/dto/index.js +0 -19
- package/dist/dto/response.dtos.d.ts +0 -55
- package/dist/dto/response.dtos.js +0 -6
- package/dist/dto/user-service.dtos.d.ts +0 -50
- package/dist/dto/user-service.dtos.js +0 -2
- package/dist/enums/auth-service.enums.d.ts +0 -12
- package/dist/enums/auth-service.enums.js +0 -17
- package/dist/enums/permissions.types.d.ts +0 -12
- package/dist/enums/permissions.types.js +0 -17
- package/dist/enums/user-service.enums.d.ts +0 -32
- package/dist/enums/user-service.enums.js +0 -41
- package/dist/internal/index.d.ts +0 -4
- package/dist/internal/index.js +0 -20
- package/dist/internal/internal-jwt.service.d.ts +0 -13
- package/dist/internal/internal-jwt.service.js +0 -88
- package/dist/internal/internal-jwt.types.d.ts +0 -7
- package/dist/internal/internal-jwt.types.js +0 -2
- package/dist/internal/internal-key-manager.d.ts +0 -16
- package/dist/internal/internal-key-manager.js +0 -67
- package/dist/internal/registry.d.ts +0 -8
- package/dist/internal/registry.js +0 -34
- package/dist/internal/service-client.d.ts +0 -9
- package/dist/internal/service-client.js +0 -94
- package/dist/jwt/internal-jwt-verifier.d.ts +0 -41
- package/dist/jwt/internal-jwt-verifier.js +0 -185
- package/dist/jwt/jwt-verifier.d.ts +0 -9
- package/dist/jwt/jwt-verifier.js +0 -36
- package/dist/jwt/service-client.d.ts +0 -7
- package/dist/jwt/service-client.js +0 -87
- package/dist/middleware/authorize.d.ts +0 -3
- package/dist/middleware/authorize.js +0 -24
- package/dist/middleware/authorize.middleware.d.ts +0 -54
- package/dist/middleware/authorize.middleware.js +0 -104
- package/dist/middleware/error-handler.d.ts +0 -4
- package/dist/middleware/error-handler.js +0 -23
- package/dist/middleware/request-id.d.ts +0 -2
- package/dist/middleware/request-id.js +0 -9
- package/dist/middleware/request-id.middleware.d.ts +0 -22
- package/dist/middleware/request-id.middleware.js +0 -34
- package/dist/middleware/require-auth.d.ts +0 -10
- package/dist/middleware/require-auth.js +0 -34
- package/dist/middleware/require-human.middleware.d.ts +0 -2
- package/dist/middleware/require-human.middleware.js +0 -18
- package/dist/middleware/require-internal.middleware.d.ts +0 -18
- package/dist/middleware/require-internal.middleware.js +0 -183
- package/dist/middleware/validate.d.ts +0 -5
- package/dist/middleware/validate.js +0 -18
- package/dist/middleware/validated-merge.middleware.d.ts +0 -20
- package/dist/middleware/validated-merge.middleware.js +0 -33
- package/dist/middleware/verify-internal-jwt.d.ts +0 -7
- package/dist/middleware/verify-internal-jwt.js +0 -25
- package/dist/security/guard.d.ts +0 -10
- package/dist/security/guard.js +0 -40
- package/dist/security/index.d.ts +0 -1
- package/dist/types/express.d.ts +0 -22
- package/dist/types/express.js +0 -3
- package/dist/utils/date.utils.d.ts +0 -25
- package/dist/utils/date.utils.js +0 -30
- package/dist/utils/env.d.ts +0 -46
- package/dist/utils/env.js +0 -61
- package/dist/utils/env.utils.d.ts +0 -46
- package/dist/utils/env.utils.js +0 -61
- package/dist/utils/logger.utils.d.ts +0 -66
- package/dist/utils/logger.utils.js +0 -97
- package/dist/utils/response.d.ts +0 -4
- package/dist/utils/response.js +0 -35
- package/dist/utils/response.utils.d.ts +0 -54
- package/dist/utils/response.utils.js +0 -85
|
@@ -1,4 +1,10 @@
|
|
|
1
1
|
"use strict";
|
|
2
|
+
/**
|
|
3
|
+
* @file service-client.ts
|
|
4
|
+
* @description HTTP client wrapper for service-to-service communication.
|
|
5
|
+
* Handles automatic JWT forwarding, request correlation tracking via header propagation,
|
|
6
|
+
* and automatic retry behaviors on transient failures.
|
|
7
|
+
*/
|
|
2
8
|
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
3
9
|
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
4
10
|
};
|
|
@@ -7,35 +13,15 @@ exports.ServiceClient = void 0;
|
|
|
7
13
|
const axios_1 = __importDefault(require("axios"));
|
|
8
14
|
const axios_retry_1 = __importDefault(require("axios-retry"));
|
|
9
15
|
/**
|
|
10
|
-
*
|
|
11
|
-
*
|
|
12
|
-
* HTTP client for service-to-service communication.
|
|
13
|
-
*
|
|
14
|
-
* Two call patterns:
|
|
15
|
-
*
|
|
16
|
-
* Pattern 1 — JWT-forwarding (user-initiated requests)
|
|
17
|
-
* Pass the current Express Request — Authorization + x-request-id are
|
|
18
|
-
* forwarded automatically. Used when the downstream service needs to
|
|
19
|
-
* act on behalf of the authenticated user.
|
|
20
|
-
* Methods: getWithAuth, postWithAuth, patchWithAuth, deleteWithAuth
|
|
21
|
-
*
|
|
22
|
-
* Pattern 2 — Internal calls (service-initiated, no incoming request)
|
|
23
|
-
* Pass explicit headers — used when calls originate from service logic
|
|
24
|
-
* rather than from an HTTP handler (e.g. auth service → user service
|
|
25
|
-
* during account creation). Caller is responsible for providing the
|
|
26
|
-
* X-Internal-Secret header.
|
|
27
|
-
* Methods: get, post, patch, delete
|
|
28
|
-
*
|
|
29
|
-
* Retry strategy:
|
|
30
|
-
* - Retries on network errors and 5xx responses only (up to 3 attempts,
|
|
31
|
-
* exponential backoff). 4xx responses are never retried — they are
|
|
32
|
-
* deterministic caller errors that won't resolve on retry.
|
|
33
|
-
*
|
|
34
|
-
* Timeout:
|
|
35
|
-
* - 8 seconds per request (covers retry delays separately via axiosRetry).
|
|
36
|
-
* Adjust per-call via config.timeout if a specific route needs more.
|
|
16
|
+
* ServiceClient encapsulates an AxiosInstance configured for service-to-service HTTP requests.
|
|
17
|
+
* Supports token forwarding (Pattern 1) and secure internal calls (Pattern 2).
|
|
37
18
|
*/
|
|
38
19
|
class ServiceClient {
|
|
20
|
+
/**
|
|
21
|
+
* Initializes the Axios instance with a base URL, timeout, and retry rules.
|
|
22
|
+
*
|
|
23
|
+
* @param {string} baseURL - Downstream service base URL.
|
|
24
|
+
*/
|
|
39
25
|
constructor(baseURL) {
|
|
40
26
|
this.http = axios_1.default.create({
|
|
41
27
|
baseURL,
|
|
@@ -45,62 +31,123 @@ class ServiceClient {
|
|
|
45
31
|
retries: 3,
|
|
46
32
|
retryDelay: axios_retry_1.default.exponentialDelay,
|
|
47
33
|
retryCondition: (err) => {
|
|
48
|
-
// Retry network-level errors (no response received)
|
|
49
34
|
if (axios_retry_1.default.isNetworkError(err))
|
|
50
35
|
return true;
|
|
51
|
-
// Retry transient server errors; never retry client errors
|
|
52
36
|
const status = err.response?.status ?? 0;
|
|
53
37
|
return status >= 500;
|
|
54
38
|
},
|
|
55
39
|
});
|
|
56
40
|
}
|
|
57
|
-
/*
|
|
58
|
-
Pattern 1 — JWT-forwarding (pass Express
|
|
59
|
-
Forwards
|
|
60
|
-
|
|
61
|
-
|
|
41
|
+
/* ---------------------------------------------------------------------------
|
|
42
|
+
Pattern 1 — JWT-forwarding (pass Express Request)
|
|
43
|
+
Forwards authorization tokens and request correlation IDs automatically.
|
|
44
|
+
--------------------------------------------------------------------------- */
|
|
45
|
+
/**
|
|
46
|
+
* Performs an HTTP GET request while forwarding authorization and request headers.
|
|
47
|
+
*
|
|
48
|
+
* @param {string} url - Request target endpoint relative path.
|
|
49
|
+
* @param {Request} req - The current Express request object.
|
|
50
|
+
* @param {AxiosRequestConfig} [config] - Optional request configuration parameters.
|
|
51
|
+
* @returns {Promise<AxiosResponse<T>>} Axios response promise.
|
|
52
|
+
*/
|
|
62
53
|
async getWithAuth(url, req, config) {
|
|
63
54
|
return this.http.get(url, this.mergeAuth(req, config));
|
|
64
55
|
}
|
|
56
|
+
/**
|
|
57
|
+
* Performs an HTTP POST request while forwarding authorization and request headers.
|
|
58
|
+
*
|
|
59
|
+
* @param {string} url - Request target endpoint relative path.
|
|
60
|
+
* @param {unknown} data - JSON request body data payload.
|
|
61
|
+
* @param {Request} req - The current Express request object.
|
|
62
|
+
* @param {AxiosRequestConfig} [config] - Optional request configuration parameters.
|
|
63
|
+
* @returns {Promise<AxiosResponse<T>>} Axios response promise.
|
|
64
|
+
*/
|
|
65
65
|
async postWithAuth(url, data, req, config) {
|
|
66
66
|
return this.http.post(url, data, this.mergeAuth(req, config));
|
|
67
67
|
}
|
|
68
|
+
/**
|
|
69
|
+
* Performs an HTTP PATCH request while forwarding authorization and request headers.
|
|
70
|
+
*
|
|
71
|
+
* @param {string} url - Request target endpoint relative path.
|
|
72
|
+
* @param {unknown} data - JSON request body data payload.
|
|
73
|
+
* @param {Request} req - The current Express request object.
|
|
74
|
+
* @param {AxiosRequestConfig} [config] - Optional request configuration parameters.
|
|
75
|
+
* @returns {Promise<AxiosResponse<T>>} Axios response promise.
|
|
76
|
+
*/
|
|
68
77
|
async patchWithAuth(url, data, req, config) {
|
|
69
78
|
return this.http.patch(url, data, this.mergeAuth(req, config));
|
|
70
79
|
}
|
|
80
|
+
/**
|
|
81
|
+
* Performs an HTTP DELETE request while forwarding authorization and request headers.
|
|
82
|
+
*
|
|
83
|
+
* @param {string} url - Request target endpoint relative path.
|
|
84
|
+
* @param {Request} req - The current Express request object.
|
|
85
|
+
* @param {AxiosRequestConfig} [config] - Optional request configuration parameters.
|
|
86
|
+
* @returns {Promise<AxiosResponse<T>>} Axios response promise.
|
|
87
|
+
*/
|
|
71
88
|
async deleteWithAuth(url, req, config) {
|
|
72
89
|
return this.http.delete(url, this.mergeAuth(req, config));
|
|
73
90
|
}
|
|
74
|
-
/*
|
|
75
|
-
Pattern 2 — Internal calls (explicit headers, no Express
|
|
76
|
-
Used for service-initiated
|
|
77
|
-
|
|
78
|
-
|
|
91
|
+
/* ---------------------------------------------------------------------------
|
|
92
|
+
Pattern 2 — Internal calls (explicit headers, no Express Request)
|
|
93
|
+
Used for background tasks or service-initiated operations without a request context.
|
|
94
|
+
--------------------------------------------------------------------------- */
|
|
95
|
+
/**
|
|
96
|
+
* Performs an HTTP GET request with explicit header configurations.
|
|
97
|
+
*
|
|
98
|
+
* @param {string} url - Request target endpoint relative path.
|
|
99
|
+
* @param {Record<string, string>} headers - Header keys and values to attach.
|
|
100
|
+
* @param {AxiosRequestConfig} [config] - Optional request configuration parameters.
|
|
101
|
+
* @returns {Promise<AxiosResponse<T>>} Axios response promise.
|
|
102
|
+
*/
|
|
79
103
|
async get(url, headers, config) {
|
|
80
104
|
return this.http.get(url, this.mergeHeaders(headers, config));
|
|
81
105
|
}
|
|
106
|
+
/**
|
|
107
|
+
* Performs an HTTP POST request with explicit header configurations.
|
|
108
|
+
*
|
|
109
|
+
* @param {string} url - Request target endpoint relative path.
|
|
110
|
+
* @param {unknown} data - JSON request body data payload.
|
|
111
|
+
* @param {Record<string, string>} headers - Header keys and values to attach.
|
|
112
|
+
* @param {AxiosRequestConfig} [config] - Optional request configuration parameters.
|
|
113
|
+
* @returns {Promise<AxiosResponse<T>>} Axios response promise.
|
|
114
|
+
*/
|
|
82
115
|
async post(url, data, headers, config) {
|
|
83
116
|
return this.http.post(url, data, this.mergeHeaders(headers, config));
|
|
84
117
|
}
|
|
118
|
+
/**
|
|
119
|
+
* Performs an HTTP PATCH request with explicit header configurations.
|
|
120
|
+
*
|
|
121
|
+
* @param {string} url - Request target endpoint relative path.
|
|
122
|
+
* @param {unknown} data - JSON request body data payload.
|
|
123
|
+
* @param {Record<string, string>} headers - Header keys and values to attach.
|
|
124
|
+
* @param {AxiosRequestConfig} [config] - Optional request configuration parameters.
|
|
125
|
+
* @returns {Promise<AxiosResponse<T>>} Axios response promise.
|
|
126
|
+
*/
|
|
85
127
|
async patch(url, data, headers, config) {
|
|
86
128
|
return this.http.patch(url, data, this.mergeHeaders(headers, config));
|
|
87
129
|
}
|
|
130
|
+
/**
|
|
131
|
+
* Performs an HTTP DELETE request with explicit header configurations.
|
|
132
|
+
*
|
|
133
|
+
* @param {string} url - Request target endpoint relative path.
|
|
134
|
+
* @param {Record<string, string>} headers - Header keys and values to attach.
|
|
135
|
+
* @param {AxiosRequestConfig} [config] - Optional request configuration parameters.
|
|
136
|
+
* @returns {Promise<AxiosResponse<T>>} Axios response promise.
|
|
137
|
+
*/
|
|
88
138
|
async delete(url, headers, config) {
|
|
89
139
|
return this.http.delete(url, this.mergeHeaders(headers, config));
|
|
90
140
|
}
|
|
91
|
-
/*
|
|
92
|
-
Private
|
|
93
|
-
|
|
141
|
+
/* ---------------------------------------------------------------------------
|
|
142
|
+
Private Helpers
|
|
143
|
+
--------------------------------------------------------------------------- */
|
|
94
144
|
/**
|
|
95
|
-
*
|
|
96
|
-
*
|
|
97
|
-
* and merges them into the Axios config headers.
|
|
145
|
+
* Extracts authorization credentials and tracing identifiers from Express requests
|
|
146
|
+
* and merges them into Axios config header values.
|
|
98
147
|
*
|
|
99
|
-
*
|
|
100
|
-
*
|
|
101
|
-
*
|
|
102
|
-
* 3. Synthetic fallback (timestamp) — should not appear in production
|
|
103
|
-
* if request-id middleware is wired correctly in the gateway
|
|
148
|
+
* @param {Request} req - The current Express request.
|
|
149
|
+
* @param {AxiosRequestConfig} [config] - The existing Axios request configuration.
|
|
150
|
+
* @returns {AxiosRequestConfig} The merged Axios request configuration.
|
|
104
151
|
*/
|
|
105
152
|
mergeAuth(req, config) {
|
|
106
153
|
const authHeader = req.headers.authorization;
|
|
@@ -116,9 +163,11 @@ class ServiceClient {
|
|
|
116
163
|
};
|
|
117
164
|
}
|
|
118
165
|
/**
|
|
119
|
-
*
|
|
120
|
-
*
|
|
121
|
-
*
|
|
166
|
+
* Integrates user-supplied headers into the request configuration object.
|
|
167
|
+
*
|
|
168
|
+
* @param {Record<string, string>} headers - The headers to merge.
|
|
169
|
+
* @param {AxiosRequestConfig} [config] - The existing Axios request configuration.
|
|
170
|
+
* @returns {AxiosRequestConfig} The merged Axios request configuration.
|
|
122
171
|
*/
|
|
123
172
|
mergeHeaders(headers, config) {
|
|
124
173
|
return {
|
package/dist/index.d.ts
CHANGED
package/dist/index.js
CHANGED
package/dist/jwt/index.d.ts
CHANGED
package/dist/jwt/index.js
CHANGED
|
@@ -14,5 +14,6 @@ var __exportStar = (this && this.__exportStar) || function(m, exports) {
|
|
|
14
14
|
for (var p in m) if (p !== "default" && !Object.prototype.hasOwnProperty.call(exports, p)) __createBinding(exports, m, p);
|
|
15
15
|
};
|
|
16
16
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
17
|
-
__exportStar(require("./
|
|
17
|
+
__exportStar(require("./user-jwt-verifier"), exports);
|
|
18
|
+
__exportStar(require("./machine-jwt-verifier"), exports);
|
|
18
19
|
__exportStar(require("./machine-token-client"), exports);
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @file machine-jwt-verifier.ts
|
|
3
|
+
* @description Verifies service-to-service RS256 machine JWTs issued by auth-service.
|
|
4
|
+
*/
|
|
5
|
+
import { MachineTokenPayload } from "../types";
|
|
6
|
+
/**
|
|
7
|
+
* Verifies auth-service issued machine tokens used for service-to-service calls.
|
|
8
|
+
*/
|
|
9
|
+
export declare class MachineJwtVerifier {
|
|
10
|
+
private readonly jwks;
|
|
11
|
+
private readonly issuer;
|
|
12
|
+
private readonly audience;
|
|
13
|
+
constructor(authServiceJwksUri?: string);
|
|
14
|
+
/**
|
|
15
|
+
* Verify machine JWT signature and claims.
|
|
16
|
+
*
|
|
17
|
+
* @param {string} token - Raw bearer machine token.
|
|
18
|
+
* @returns {Promise<MachineTokenPayload>} Verified machine payload.
|
|
19
|
+
*/
|
|
20
|
+
verify(token: string): Promise<MachineTokenPayload>;
|
|
21
|
+
}
|
|
@@ -0,0 +1,84 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
/**
|
|
3
|
+
* @file machine-jwt-verifier.ts
|
|
4
|
+
* @description Verifies service-to-service RS256 machine JWTs issued by auth-service.
|
|
5
|
+
*/
|
|
6
|
+
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
|
|
7
|
+
if (k2 === undefined) k2 = k;
|
|
8
|
+
var desc = Object.getOwnPropertyDescriptor(m, k);
|
|
9
|
+
if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
|
|
10
|
+
desc = { enumerable: true, get: function() { return m[k]; } };
|
|
11
|
+
}
|
|
12
|
+
Object.defineProperty(o, k2, desc);
|
|
13
|
+
}) : (function(o, m, k, k2) {
|
|
14
|
+
if (k2 === undefined) k2 = k;
|
|
15
|
+
o[k2] = m[k];
|
|
16
|
+
}));
|
|
17
|
+
var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
|
|
18
|
+
Object.defineProperty(o, "default", { enumerable: true, value: v });
|
|
19
|
+
}) : function(o, v) {
|
|
20
|
+
o["default"] = v;
|
|
21
|
+
});
|
|
22
|
+
var __importStar = (this && this.__importStar) || (function () {
|
|
23
|
+
var ownKeys = function(o) {
|
|
24
|
+
ownKeys = Object.getOwnPropertyNames || function (o) {
|
|
25
|
+
var ar = [];
|
|
26
|
+
for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
|
|
27
|
+
return ar;
|
|
28
|
+
};
|
|
29
|
+
return ownKeys(o);
|
|
30
|
+
};
|
|
31
|
+
return function (mod) {
|
|
32
|
+
if (mod && mod.__esModule) return mod;
|
|
33
|
+
var result = {};
|
|
34
|
+
if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
|
|
35
|
+
__setModuleDefault(result, mod);
|
|
36
|
+
return result;
|
|
37
|
+
};
|
|
38
|
+
})();
|
|
39
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
40
|
+
exports.MachineJwtVerifier = void 0;
|
|
41
|
+
const jose = __importStar(require("jose"));
|
|
42
|
+
const CLOCK_TOLERANCE_SECONDS = 30;
|
|
43
|
+
const JWKS_CACHE_MAX_AGE_MS = 10 * 60 * 1000;
|
|
44
|
+
const JWKS_FETCH_TIMEOUT_MS = 5000;
|
|
45
|
+
/**
|
|
46
|
+
* Verifies auth-service issued machine tokens used for service-to-service calls.
|
|
47
|
+
*/
|
|
48
|
+
class MachineJwtVerifier {
|
|
49
|
+
constructor(authServiceJwksUri) {
|
|
50
|
+
const jwksUri = authServiceJwksUri ??
|
|
51
|
+
process.env.AUTH_JWKS_URI ??
|
|
52
|
+
"http://auth-service:3001/.well-known/jwks.json";
|
|
53
|
+
this.issuer = process.env.MACHINE_JWT_ISSUER ?? "discover-cloud:auth-service";
|
|
54
|
+
this.audience = process.env.MACHINE_JWT_AUDIENCE ?? "discover-cloud:services";
|
|
55
|
+
this.jwks = jose.createRemoteJWKSet(new URL(jwksUri), {
|
|
56
|
+
cacheMaxAge: JWKS_CACHE_MAX_AGE_MS,
|
|
57
|
+
timeoutDuration: JWKS_FETCH_TIMEOUT_MS,
|
|
58
|
+
});
|
|
59
|
+
}
|
|
60
|
+
/**
|
|
61
|
+
* Verify machine JWT signature and claims.
|
|
62
|
+
*
|
|
63
|
+
* @param {string} token - Raw bearer machine token.
|
|
64
|
+
* @returns {Promise<MachineTokenPayload>} Verified machine payload.
|
|
65
|
+
*/
|
|
66
|
+
async verify(token) {
|
|
67
|
+
const { payload } = await jose.jwtVerify(token, this.jwks, {
|
|
68
|
+
issuer: this.issuer,
|
|
69
|
+
audience: this.audience,
|
|
70
|
+
algorithms: ["RS256"],
|
|
71
|
+
clockTolerance: CLOCK_TOLERANCE_SECONDS,
|
|
72
|
+
});
|
|
73
|
+
if (payload.typ !== "machine") {
|
|
74
|
+
throw new jose.errors.JWTClaimValidationFailed(`Token type mismatch: expected "machine", got "${String(payload.typ)}"`, payload, "typ", "check_failed");
|
|
75
|
+
}
|
|
76
|
+
if (typeof payload.serviceId !== "string" ||
|
|
77
|
+
typeof payload.jti !== "string" ||
|
|
78
|
+
!Array.isArray(payload.scopes)) {
|
|
79
|
+
throw new jose.errors.JWTClaimValidationFailed("Missing required machine token claims", payload, "payload", "missing");
|
|
80
|
+
}
|
|
81
|
+
return payload;
|
|
82
|
+
}
|
|
83
|
+
}
|
|
84
|
+
exports.MachineJwtVerifier = MachineJwtVerifier;
|
|
@@ -1,13 +1,44 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @file machine-token-client.ts
|
|
3
|
+
* @description HTTP client for fetching and caching short-lived machine JWTs
|
|
4
|
+
* from the Auth Service for service-to-service communication.
|
|
5
|
+
*/
|
|
1
6
|
import { ILogger } from "../utils";
|
|
7
|
+
/**
|
|
8
|
+
* Handles retrieving and caching auth-service issued machine JWTs.
|
|
9
|
+
*/
|
|
2
10
|
export declare class MachineTokenClient {
|
|
3
|
-
private readonly
|
|
11
|
+
private readonly authServiceUrl;
|
|
4
12
|
private readonly serviceId;
|
|
5
|
-
private readonly
|
|
13
|
+
private readonly serviceSecret;
|
|
6
14
|
private readonly logger;
|
|
7
15
|
private cache;
|
|
8
16
|
private fetchPromise;
|
|
9
|
-
|
|
17
|
+
/**
|
|
18
|
+
* @param {string} authServiceUrl - Base URL of the Auth Service.
|
|
19
|
+
* @param {string} serviceId - The service ID identifying the calling microservice.
|
|
20
|
+
* @param {string} serviceSecret - Service-specific secret for authentication.
|
|
21
|
+
* @param {ILogger} [logger] - Optional logger instance.
|
|
22
|
+
*/
|
|
23
|
+
constructor(authServiceUrl: string, serviceId: string, serviceSecret: string, logger?: ILogger);
|
|
24
|
+
/**
|
|
25
|
+
* Returns a valid machine JWT.
|
|
26
|
+
*
|
|
27
|
+
* @param {string} [requestId] - Request ID for distributed tracing.
|
|
28
|
+
* @returns {Promise<string>} The machine JWT token string.
|
|
29
|
+
*/
|
|
10
30
|
getToken(requestId?: string): Promise<string>;
|
|
11
|
-
|
|
31
|
+
/**
|
|
32
|
+
* Gets the cached token if it exists and is not within the refresh buffer window.
|
|
33
|
+
*
|
|
34
|
+
* @returns {CachedToken | null} The cached token, or null if invalid/expired.
|
|
35
|
+
*/
|
|
36
|
+
private getCachedToken;
|
|
37
|
+
/**
|
|
38
|
+
* Performs the HTTP request to the Auth Service to retrieve a machine token.
|
|
39
|
+
*
|
|
40
|
+
* @param {string} [requestId] - Request ID for tracing.
|
|
41
|
+
* @returns {Promise<string>} The freshly issued machine token.
|
|
42
|
+
*/
|
|
12
43
|
private fetchToken;
|
|
13
44
|
}
|
|
@@ -1,21 +1,41 @@
|
|
|
1
1
|
"use strict";
|
|
2
|
+
/**
|
|
3
|
+
* @file machine-token-client.ts
|
|
4
|
+
* @description HTTP client for fetching and caching short-lived machine JWTs
|
|
5
|
+
* from the Auth Service for service-to-service communication.
|
|
6
|
+
*/
|
|
2
7
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
8
|
exports.MachineTokenClient = void 0;
|
|
4
9
|
const utils_1 = require("../utils");
|
|
5
|
-
const
|
|
10
|
+
const REFRESH_BUFFER_SECONDS = 60;
|
|
11
|
+
/**
|
|
12
|
+
* Handles retrieving and caching auth-service issued machine JWTs.
|
|
13
|
+
*/
|
|
6
14
|
class MachineTokenClient {
|
|
7
|
-
|
|
8
|
-
|
|
15
|
+
/**
|
|
16
|
+
* @param {string} authServiceUrl - Base URL of the Auth Service.
|
|
17
|
+
* @param {string} serviceId - The service ID identifying the calling microservice.
|
|
18
|
+
* @param {string} serviceSecret - Service-specific secret for authentication.
|
|
19
|
+
* @param {ILogger} [logger] - Optional logger instance.
|
|
20
|
+
*/
|
|
21
|
+
constructor(authServiceUrl, serviceId, serviceSecret, logger = utils_1.noopLogger) {
|
|
22
|
+
this.authServiceUrl = authServiceUrl;
|
|
9
23
|
this.serviceId = serviceId;
|
|
10
|
-
this.
|
|
24
|
+
this.serviceSecret = serviceSecret;
|
|
11
25
|
this.logger = logger;
|
|
12
26
|
this.cache = null;
|
|
13
27
|
this.fetchPromise = null;
|
|
14
28
|
}
|
|
29
|
+
/**
|
|
30
|
+
* Returns a valid machine JWT.
|
|
31
|
+
*
|
|
32
|
+
* @param {string} [requestId] - Request ID for distributed tracing.
|
|
33
|
+
* @returns {Promise<string>} The machine JWT token string.
|
|
34
|
+
*/
|
|
15
35
|
async getToken(requestId) {
|
|
16
|
-
const
|
|
17
|
-
if (
|
|
18
|
-
return
|
|
36
|
+
const cached = this.getCachedToken();
|
|
37
|
+
if (cached) {
|
|
38
|
+
return cached.token;
|
|
19
39
|
}
|
|
20
40
|
if (!this.fetchPromise) {
|
|
21
41
|
this.fetchPromise = this.fetchToken(requestId).finally(() => {
|
|
@@ -24,44 +44,58 @@ class MachineTokenClient {
|
|
|
24
44
|
}
|
|
25
45
|
return this.fetchPromise;
|
|
26
46
|
}
|
|
27
|
-
|
|
47
|
+
/**
|
|
48
|
+
* Gets the cached token if it exists and is not within the refresh buffer window.
|
|
49
|
+
*
|
|
50
|
+
* @returns {CachedToken | null} The cached token, or null if invalid/expired.
|
|
51
|
+
*/
|
|
52
|
+
getCachedToken() {
|
|
28
53
|
if (!this.cache) {
|
|
29
54
|
return null;
|
|
30
55
|
}
|
|
31
|
-
const
|
|
32
|
-
if (this.cache.expiresAt -
|
|
56
|
+
const now = Math.floor(Date.now() / 1000);
|
|
57
|
+
if (this.cache.expiresAt - REFRESH_BUFFER_SECONDS <= now) {
|
|
33
58
|
return null;
|
|
34
59
|
}
|
|
35
60
|
return this.cache;
|
|
36
61
|
}
|
|
62
|
+
/**
|
|
63
|
+
* Performs the HTTP request to the Auth Service to retrieve a machine token.
|
|
64
|
+
*
|
|
65
|
+
* @param {string} [requestId] - Request ID for tracing.
|
|
66
|
+
* @returns {Promise<string>} The freshly issued machine token.
|
|
67
|
+
*/
|
|
37
68
|
async fetchToken(requestId) {
|
|
38
|
-
const url = `${this.
|
|
69
|
+
const url = `${this.authServiceUrl.replace(/\/$/, "")}/internal/machine-token`;
|
|
39
70
|
this.logger.debug({ serviceId: this.serviceId, requestId }, "Fetching machine token");
|
|
40
|
-
const headers = {
|
|
41
|
-
"content-type": "application/json",
|
|
42
|
-
};
|
|
43
|
-
if (this.internalSecret) {
|
|
44
|
-
headers["x-internal-secret"] = this.internalSecret;
|
|
45
|
-
}
|
|
46
71
|
const response = await fetch(url, {
|
|
47
72
|
method: "POST",
|
|
48
|
-
headers
|
|
73
|
+
headers: {
|
|
74
|
+
"content-type": "application/json",
|
|
75
|
+
},
|
|
49
76
|
body: JSON.stringify({
|
|
50
77
|
serviceId: this.serviceId,
|
|
78
|
+
secret: this.serviceSecret,
|
|
51
79
|
requestId,
|
|
52
80
|
}),
|
|
53
81
|
});
|
|
54
82
|
if (!response.ok) {
|
|
55
83
|
const text = await response.text().catch(() => "(unreadable)");
|
|
56
|
-
throw new Error(`
|
|
84
|
+
throw new Error(`Machine token request failed (${response.status}): ${text}`);
|
|
57
85
|
}
|
|
58
86
|
const body = (await response.json());
|
|
59
|
-
|
|
87
|
+
if (!body.success ||
|
|
88
|
+
!body.data?.accessToken ||
|
|
89
|
+
typeof body.data.expiresIn !== "number" ||
|
|
90
|
+
body.data.expiresIn <= 0) {
|
|
91
|
+
throw new Error("Invalid machine token response");
|
|
92
|
+
}
|
|
93
|
+
const now = Math.floor(Date.now() / 1000);
|
|
60
94
|
this.cache = {
|
|
61
|
-
token: body.data.
|
|
62
|
-
expiresAt:
|
|
95
|
+
token: body.data.accessToken,
|
|
96
|
+
expiresAt: now + body.data.expiresIn,
|
|
63
97
|
};
|
|
64
|
-
this.logger.
|
|
98
|
+
this.logger.debug({
|
|
65
99
|
serviceId: this.serviceId,
|
|
66
100
|
expiresAt: this.cache.expiresAt,
|
|
67
101
|
}, "Machine token cached");
|
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @file user-jwt-verifier.ts
|
|
3
|
+
* @description Verifies user RS256 access tokens issued by auth-service.
|
|
4
|
+
*/
|
|
5
|
+
import { AccessTokenPayload, UserContext } from "../types";
|
|
6
|
+
/**
|
|
7
|
+
* Verifies auth-service issued user access tokens.
|
|
8
|
+
*/
|
|
9
|
+
export declare class UserJwtVerifier {
|
|
10
|
+
private readonly jwks;
|
|
11
|
+
private readonly issuer;
|
|
12
|
+
private readonly audience;
|
|
13
|
+
constructor();
|
|
14
|
+
/**
|
|
15
|
+
* Verify JWT signature and required user claims.
|
|
16
|
+
*
|
|
17
|
+
* @param {string} token - Raw bearer access token.
|
|
18
|
+
* @returns {Promise<AccessTokenPayload>} Verified access payload.
|
|
19
|
+
*/
|
|
20
|
+
verify(token: string): Promise<AccessTokenPayload>;
|
|
21
|
+
/**
|
|
22
|
+
* Builds request authorization context.
|
|
23
|
+
*
|
|
24
|
+
* @param {string} token - Raw bearer access token.
|
|
25
|
+
* @returns {Promise<{ payload: AccessTokenPayload; context: UserContext }>} The auth context block.
|
|
26
|
+
*/
|
|
27
|
+
buildAccessContext(token: string): Promise<{
|
|
28
|
+
payload: AccessTokenPayload;
|
|
29
|
+
context: UserContext;
|
|
30
|
+
}>;
|
|
31
|
+
}
|
|
@@ -0,0 +1,101 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
/**
|
|
3
|
+
* @file user-jwt-verifier.ts
|
|
4
|
+
* @description Verifies user RS256 access tokens issued by auth-service.
|
|
5
|
+
*/
|
|
6
|
+
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
|
|
7
|
+
if (k2 === undefined) k2 = k;
|
|
8
|
+
var desc = Object.getOwnPropertyDescriptor(m, k);
|
|
9
|
+
if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
|
|
10
|
+
desc = { enumerable: true, get: function() { return m[k]; } };
|
|
11
|
+
}
|
|
12
|
+
Object.defineProperty(o, k2, desc);
|
|
13
|
+
}) : (function(o, m, k, k2) {
|
|
14
|
+
if (k2 === undefined) k2 = k;
|
|
15
|
+
o[k2] = m[k];
|
|
16
|
+
}));
|
|
17
|
+
var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
|
|
18
|
+
Object.defineProperty(o, "default", { enumerable: true, value: v });
|
|
19
|
+
}) : function(o, v) {
|
|
20
|
+
o["default"] = v;
|
|
21
|
+
});
|
|
22
|
+
var __importStar = (this && this.__importStar) || (function () {
|
|
23
|
+
var ownKeys = function(o) {
|
|
24
|
+
ownKeys = Object.getOwnPropertyNames || function (o) {
|
|
25
|
+
var ar = [];
|
|
26
|
+
for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
|
|
27
|
+
return ar;
|
|
28
|
+
};
|
|
29
|
+
return ownKeys(o);
|
|
30
|
+
};
|
|
31
|
+
return function (mod) {
|
|
32
|
+
if (mod && mod.__esModule) return mod;
|
|
33
|
+
var result = {};
|
|
34
|
+
if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
|
|
35
|
+
__setModuleDefault(result, mod);
|
|
36
|
+
return result;
|
|
37
|
+
};
|
|
38
|
+
})();
|
|
39
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
40
|
+
exports.UserJwtVerifier = void 0;
|
|
41
|
+
const jose = __importStar(require("jose"));
|
|
42
|
+
const CLOCK_TOLERANCE_SECONDS = 30;
|
|
43
|
+
const JWKS_CACHE_MAX_AGE_MS = 10 * 60 * 1000;
|
|
44
|
+
const JWKS_FETCH_TIMEOUT_MS = 5000;
|
|
45
|
+
/**
|
|
46
|
+
* Verifies auth-service issued user access tokens.
|
|
47
|
+
*/
|
|
48
|
+
class UserJwtVerifier {
|
|
49
|
+
constructor() {
|
|
50
|
+
const authJwksUri = process.env.AUTH_JWKS_URI ?? "http://auth-service:3001/.well-known/jwks.json";
|
|
51
|
+
this.issuer = process.env.EXTERNAL_JWT_ISSUER ?? "discover-cloud:auth-service";
|
|
52
|
+
this.audience = process.env.EXTERNAL_JWT_AUDIENCE ?? "discover-cloud:api";
|
|
53
|
+
this.jwks = jose.createRemoteJWKSet(new URL(authJwksUri), {
|
|
54
|
+
cacheMaxAge: JWKS_CACHE_MAX_AGE_MS,
|
|
55
|
+
timeoutDuration: JWKS_FETCH_TIMEOUT_MS,
|
|
56
|
+
});
|
|
57
|
+
}
|
|
58
|
+
/**
|
|
59
|
+
* Verify JWT signature and required user claims.
|
|
60
|
+
*
|
|
61
|
+
* @param {string} token - Raw bearer access token.
|
|
62
|
+
* @returns {Promise<AccessTokenPayload>} Verified access payload.
|
|
63
|
+
*/
|
|
64
|
+
async verify(token) {
|
|
65
|
+
const { payload } = await jose.jwtVerify(token, this.jwks, {
|
|
66
|
+
issuer: this.issuer,
|
|
67
|
+
audience: this.audience,
|
|
68
|
+
algorithms: ["RS256"],
|
|
69
|
+
clockTolerance: CLOCK_TOLERANCE_SECONDS,
|
|
70
|
+
});
|
|
71
|
+
if (payload.typ !== "access") {
|
|
72
|
+
throw new jose.errors.JWTClaimValidationFailed(`Token type mismatch: expected "access", got "${String(payload.typ)}"`, payload, "typ", "check_failed");
|
|
73
|
+
}
|
|
74
|
+
if (typeof payload.accountId !== "string" ||
|
|
75
|
+
typeof payload.sessionId !== "string" ||
|
|
76
|
+
typeof payload.jti !== "string" ||
|
|
77
|
+
typeof payload.iat !== "number" ||
|
|
78
|
+
typeof payload.exp !== "number") {
|
|
79
|
+
throw new jose.errors.JWTClaimValidationFailed("Missing required access token claims", payload, "payload", "missing");
|
|
80
|
+
}
|
|
81
|
+
return payload;
|
|
82
|
+
}
|
|
83
|
+
/**
|
|
84
|
+
* Builds request authorization context.
|
|
85
|
+
*
|
|
86
|
+
* @param {string} token - Raw bearer access token.
|
|
87
|
+
* @returns {Promise<{ payload: AccessTokenPayload; context: UserContext }>} The auth context block.
|
|
88
|
+
*/
|
|
89
|
+
async buildAccessContext(token) {
|
|
90
|
+
const payload = await this.verify(token);
|
|
91
|
+
return {
|
|
92
|
+
payload,
|
|
93
|
+
context: {
|
|
94
|
+
type: "user",
|
|
95
|
+
accountId: payload.accountId,
|
|
96
|
+
sessionId: payload.sessionId,
|
|
97
|
+
},
|
|
98
|
+
};
|
|
99
|
+
}
|
|
100
|
+
}
|
|
101
|
+
exports.UserJwtVerifier = UserJwtVerifier;
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export * from './rabbitmq.client';
|
|
@@ -14,4 +14,4 @@ var __exportStar = (this && this.__exportStar) || function(m, exports) {
|
|
|
14
14
|
for (var p in m) if (p !== "default" && !Object.prototype.hasOwnProperty.call(exports, p)) __createBinding(exports, m, p);
|
|
15
15
|
};
|
|
16
16
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
17
|
-
__exportStar(require("./
|
|
17
|
+
__exportStar(require("./rabbitmq.client"), exports);
|