@sap-ux/backend-proxy-middleware-cf 0.0.50 → 0.0.52

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/README.md CHANGED
@@ -30,10 +30,11 @@ server:
30
30
  - name: backend-proxy-middleware-cf
31
31
  afterMiddleware: compression
32
32
  configuration:
33
- url: https://your-backend-service
34
- paths:
35
- - /odata/v4/visitorservice
36
- - /odata
33
+ backends:
34
+ - url: https://your-backend-service
35
+ paths:
36
+ - /odata/v4/visitorservice
37
+ - /odata
37
38
  ```
38
39
 
39
40
  ### [Automatic Detection (Recommended)](#automatic-detection-recommended)
@@ -46,10 +47,11 @@ server:
46
47
  - name: backend-proxy-middleware-cf
47
48
  afterMiddleware: compression
48
49
  configuration:
49
- url: https://your-backend-service
50
- paths:
51
- - /odata/v4/visitorservice
52
- - /odata
50
+ backends:
51
+ - url: https://your-backend-service
52
+ paths:
53
+ - /odata/v4/visitorservice
54
+ - /odata
53
55
  ```
54
56
 
55
57
  The middleware will:
@@ -70,20 +72,61 @@ server:
70
72
  - name: backend-proxy-middleware-cf
71
73
  afterMiddleware: compression
72
74
  configuration:
73
- url: https://your-backend-service
74
- paths:
75
- - /odata/v4/visitorservice
76
- - /odata
77
- credentials:
78
- clientId: "your-service-instance!b123|your-app!b456"
79
- clientSecret: "your-client-secret"
80
- url: "https://example.authentication"
81
- debug: true
75
+ backends:
76
+ - url: https://your-backend-service
77
+ paths:
78
+ - /odata/v4/visitorservice
79
+ - /odata
80
+ credentials:
81
+ clientId: "sb-your-service-instance!b123|your-app!b456"
82
+ clientSecret: "your-client-secret"
83
+ url: "https://example.authentication"
84
+ debug: true
82
85
  ```
83
86
 
84
87
  The `credentials.url` should be the base URL of the UAA service (without `/oauth/token`). The middleware will automatically construct the full token endpoint.
85
88
 
86
- ### [With Debug Logging](#with-debug-logging)
89
+ ### Multiple OData Sources
90
+
91
+ You can proxy multiple OData paths to the same destination:
92
+
93
+ ```yaml
94
+ server:
95
+ customMiddleware:
96
+ - name: backend-proxy-middleware-cf
97
+ afterMiddleware: compression
98
+ configuration:
99
+ backends:
100
+ - url: https://your-backend-service
101
+ paths:
102
+ - /odata/v4/service1
103
+ - /odata/v4/service2
104
+ - /odata/v2/legacy
105
+ ```
106
+ ### Miltiple Backend Services
107
+
108
+ You can proxy multiple backend services:
109
+
110
+ ```yaml
111
+ server:
112
+ customMiddleware:
113
+ - name: backend-proxy-middleware-cf
114
+ afterMiddleware: compression
115
+ configuration:
116
+ backends:
117
+ - url: https://your-backend-service1
118
+ paths:
119
+ - /odata/v4/service1
120
+ - /odata/v4/service2
121
+ - /odata/v2/legacy
122
+ - url: https://your-backend-service2
123
+ paths:
124
+ - /odata/v4/service1
125
+ - /odata/v4/service2
126
+ - /odata/v2/legacy
127
+ ```
128
+
129
+ ### With Debug Logging
87
130
 
88
131
  Enable debug logging to troubleshoot issues:
89
132
 
@@ -93,15 +136,47 @@ server:
93
136
  - name: backend-proxy-middleware-cf
94
137
  afterMiddleware: compression
95
138
  configuration:
96
- url: https://your-backend-service
97
- paths:
98
- - /odata
99
- debug: true
139
+ backends:
140
+ - url: https://your-backend-service.cfapps.eu12.hana.ondemand.com
141
+ paths:
142
+ - /odata
143
+ debug: true
100
144
  ```
101
145
 
102
- ## [Keywords](#keywords)
146
+ ## How It Works
147
+
148
+ 1. **Proxy Setup**: Creates HTTP proxy middleware for each configured path, proxying to the destination URL.
149
+ 2. **Path Rewriting**: Removes the matched path prefix before forwarding requests (e.g., `/odata/v4/service` → `/service`).
150
+ 3. **OAuth Detection**: For automatic mode, checks if the project is a CF ADP project by reading `ui5.yaml` and looking for the `app-variant-bundler-build` custom task.
151
+ 4. **Credentials**: Extracts `serviceInstanceName` and `serviceInstanceGuid` from the custom task configuration.
152
+ 5. **Service Keys**: Retrieves service keys using `@sap-ux/adp-tooling`, which communicates with Cloud Foundry CLI.
153
+ 6. **Token Endpoint**: Constructs the token endpoint from the UAA base URL as `{url}/oauth/token`.
154
+ 7. **Token Management**: Requests OAuth tokens using client credentials flow.
155
+ 8. **Caching**: Caches tokens in memory and refreshes them automatically 60 seconds before expiry.
156
+ 9. **Request Proxying**: Adds `Authorization: Bearer <token>` header to proxied requests before forwarding.
157
+
158
+ ## Error Handling
159
+
160
+ - If `url` is not provided, the middleware will be inactive and log a warning.
161
+ - If no paths are configured, the middleware will be inactive and log a warning.
162
+ - If auto-detection fails and no manual credentials are provided, the middleware will proxy requests without OAuth tokens (may fail if backend requires authentication).
163
+ - If token request fails, an error is logged but the request may still proceed (depending on the backend's authentication requirements).
164
+ - All errors are logged for debugging purposes.
165
+
166
+ ## Security Considerations
167
+
168
+ - Credentials are never logged in production mode.
169
+ - Tokens are cached in memory only and never persisted to disk.
170
+ - Token refresh happens automatically 60 seconds before expiry to avoid using expired tokens.
171
+ - Service keys are obtained securely through Cloud Foundry CLI.
172
+ - The middleware only proxies requests matching any of the configured path prefixes.
173
+ - If no paths are configured, the middleware will be inactive and log a warning.
174
+
175
+ ## Keywords
103
176
 
104
- - OAuth2 Proxy Middleware
177
+ - OAuth2 Middleware
105
178
  - Cloud Foundry ADP
179
+ - Bearer Token
106
180
  - Fiori tools
107
181
  - SAP UI5
182
+ - Proxy Middleware
@@ -6,7 +6,7 @@ const validation_1 = require("./validation");
6
6
  const token_1 = require("./token");
7
7
  /**
8
8
  * UI5 middleware for proxying requests to Cloud Foundry destinations with OAuth2 authentication.
9
- * Supports one destination URL with multiple OData source paths.
9
+ * Supports multiple destination URLs with their own OData source paths.
10
10
  *
11
11
  * @param {MiddlewareParameters<CfOAuthMiddlewareConfig>} params - Input parameters for UI5 middleware.
12
12
  * @param {CfOAuthMiddlewareConfig} params.options - Configuration options.
@@ -23,6 +23,12 @@ module.exports = async ({ options }) => {
23
23
  });
24
24
  await (0, validation_1.validateConfig)(config, logger);
25
25
  const tokenProvider = await (0, token_1.createTokenProvider)(config, logger);
26
- return (0, proxy_1.setupProxyRoutes)(config.paths, config.url, tokenProvider, logger);
26
+ // Setup proxy routes for all backends
27
+ const router = (0, proxy_1.setupProxyRoutes)(config.backends, tokenProvider, logger);
28
+ // Log initialization
29
+ config.backends.forEach((backend) => {
30
+ logger.info(`Backend proxy middleware (CF) initialized: url=${backend.url}, paths=${backend.paths.join(', ')}`);
31
+ });
32
+ return router;
27
33
  };
28
34
  //# sourceMappingURL=middleware.js.map
package/dist/proxy.d.ts CHANGED
@@ -24,13 +24,15 @@ export declare function createProxyOptions(targetUrl: string, logger: ToolsLogge
24
24
  */
25
25
  export declare function registerProxyRoute(path: string, destinationUrl: string, tokenProvider: OAuthTokenProvider, logger: ToolsLogger, router: Router): void;
26
26
  /**
27
- * Sets up all proxy routes for the configured paths.
27
+ * Sets up all proxy routes for the configured backends.
28
28
  *
29
- * @param {string[]} paths - Array of paths to register.
30
- * @param {string} destinationUrl - Target URL for proxying.
29
+ * @param {Array<{url: string, paths: string[]}>} backends - Array of backend configurations.
31
30
  * @param {OAuthTokenProvider} tokenProvider - Token provider instance.
32
31
  * @param {ToolsLogger} logger - Logger instance.
33
32
  * @returns {Router} Configured Express router.
34
33
  */
35
- export declare function setupProxyRoutes(paths: string[], destinationUrl: string, tokenProvider: OAuthTokenProvider, logger: ToolsLogger): Router;
34
+ export declare function setupProxyRoutes(backends: Array<{
35
+ url: string;
36
+ paths: string[];
37
+ }>, tokenProvider: OAuthTokenProvider, logger: ToolsLogger): Router;
36
38
  //# sourceMappingURL=proxy.d.ts.map
package/dist/proxy.js CHANGED
@@ -53,22 +53,23 @@ function registerProxyRoute(path, destinationUrl, tokenProvider, logger, router)
53
53
  logger.info(`Registered proxy for path: ${path} -> ${destinationUrl}`);
54
54
  }
55
55
  /**
56
- * Sets up all proxy routes for the configured paths.
56
+ * Sets up all proxy routes for the configured backends.
57
57
  *
58
- * @param {string[]} paths - Array of paths to register.
59
- * @param {string} destinationUrl - Target URL for proxying.
58
+ * @param {Array<{url: string, paths: string[]}>} backends - Array of backend configurations.
60
59
  * @param {OAuthTokenProvider} tokenProvider - Token provider instance.
61
60
  * @param {ToolsLogger} logger - Logger instance.
62
61
  * @returns {Router} Configured Express router.
63
62
  */
64
- function setupProxyRoutes(paths, destinationUrl, tokenProvider, logger) {
63
+ function setupProxyRoutes(backends, tokenProvider, logger) {
65
64
  const router = (0, express_1.Router)();
66
- for (const path of paths) {
67
- try {
68
- registerProxyRoute(path, destinationUrl, tokenProvider, logger, router);
69
- }
70
- catch (e) {
71
- throw new Error(`Failed to register proxy for ${path}. Check configuration in yaml file. \n\t${e.message}`);
65
+ for (const backend of backends) {
66
+ for (const path of backend.paths) {
67
+ try {
68
+ registerProxyRoute(path, backend.url, tokenProvider, logger, router);
69
+ }
70
+ catch (e) {
71
+ throw new Error(`Failed to register proxy for ${path}. Check configuration in yaml file. \n\t${e.message}`);
72
+ }
72
73
  }
73
74
  }
74
75
  return router;
package/dist/types.d.ts CHANGED
@@ -1,7 +1,7 @@
1
1
  /**
2
- * Configuration for Cloud Foundry OAuth middleware.
2
+ * Configuration for a single backend destination.
3
3
  */
4
- export interface CfOAuthMiddlewareConfig {
4
+ export interface BackendDestination {
5
5
  /**
6
6
  * Destination URL to proxy requests to.
7
7
  */
@@ -12,6 +12,16 @@ export interface CfOAuthMiddlewareConfig {
12
12
  * Requests matching these paths will have the path prefix removed before forwarding.
13
13
  */
14
14
  paths: string[];
15
+ }
16
+ /**
17
+ * Configuration for Cloud Foundry OAuth middleware.
18
+ */
19
+ export interface CfOAuthMiddlewareConfig {
20
+ /**
21
+ * Array of backend destinations.
22
+ * Each destination has its own URL and paths.
23
+ */
24
+ backends: BackendDestination[];
15
25
  /**
16
26
  * Manual OAuth credentials (optional).
17
27
  * If not provided, middleware will attempt to auto-detect from Cloud Foundry ADP project.
@@ -10,11 +10,17 @@ const adp_tooling_1 = require("@sap-ux/adp-tooling");
10
10
  * @throws {Error} If configuration is invalid.
11
11
  */
12
12
  async function validateConfig(config, logger) {
13
- if (!config.url) {
14
- throw new Error('Backend proxy middleware (CF) requires url configuration.');
13
+ if (!config.backends || !Array.isArray(config.backends) || config.backends.length === 0) {
14
+ throw new Error('Backend proxy middleware (CF) requires "backends" array configuration.');
15
15
  }
16
- if (!config.paths || !Array.isArray(config.paths) || config.paths.length === 0) {
17
- throw new Error('Backend proxy middleware (CF) has no paths configured.');
16
+ // Validate each backend
17
+ for (const backend of config.backends) {
18
+ if (!backend.url) {
19
+ throw new Error('Backend proxy middleware (CF) requires url for each backend.');
20
+ }
21
+ if (!backend.paths || !Array.isArray(backend.paths) || backend.paths.length === 0) {
22
+ throw new Error(`Backend proxy middleware (CF) has no paths configured for URL: ${backend.url}`);
23
+ }
18
24
  }
19
25
  const cfConfig = (0, adp_tooling_1.loadCfConfig)(logger);
20
26
  if (!(await (0, adp_tooling_1.isLoggedInCf)(cfConfig, logger))) {
package/package.json CHANGED
@@ -9,7 +9,7 @@
9
9
  "bugs": {
10
10
  "url": "https://github.com/SAP/open-ux-tools/issues?q=is%3Aopen+is%3Aissue+label%3Abug+label%3Abackend-proxy-middleware-cf"
11
11
  },
12
- "version": "0.0.50",
12
+ "version": "0.0.52",
13
13
  "license": "Apache-2.0",
14
14
  "author": "@SAP/ux-tools-team",
15
15
  "main": "dist/index.js",
@@ -23,9 +23,9 @@
23
23
  "dependencies": {
24
24
  "axios": "1.13.5",
25
25
  "http-proxy-middleware": "3.0.5",
26
- "@sap-ux/adp-tooling": "0.18.60",
26
+ "@sap-ux/adp-tooling": "0.18.62",
27
27
  "@sap-ux/logger": "0.8.1",
28
- "@sap-ux/project-access": "1.35.1"
28
+ "@sap-ux/project-access": "1.35.3"
29
29
  },
30
30
  "devDependencies": {
31
31
  "@types/express": "4.17.21",