@boxyhq/saml-jackson 0.1.5-beta.115 → 0.1.5-beta.119
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/.github/workflows/main.yml +1 -1
- package/README.md +88 -60
- package/package.json +1 -1
- package/src/controller/oauth.js +2 -12
- package/src/controller/utils.js +11 -0
- package/src/env.js +3 -0
- package/src/jackson.js +11 -0
package/README.md
CHANGED
@@ -1,33 +1,36 @@
|
|
1
1
|
# SAML Jackson (not fiction anymore)
|
2
|
-
|
2
|
+
|
3
3
|
SAML service [SAML in a box from BoxyHQ]
|
4
|
-
|
4
|
+
|
5
5
|
You need someone like Jules Winnfield to save you from the vagaries of SAML login.
|
6
|
-
|
6
|
+
|
7
7
|
# Source code visualizer
|
8
|
+
|
8
9
|
[CodeSee codebase visualizer](https://app.codesee.io/maps/public/53e91640-23b5-11ec-a724-79d7dd589517)
|
9
|
-
|
10
|
+
|
10
11
|
# Getting Started
|
11
|
-
|
12
|
+
|
12
13
|
There are two ways to use this repo.
|
14
|
+
|
13
15
|
- As an npm library (for Express compatible frameworks)
|
14
16
|
- As a separate service
|
15
|
-
|
17
|
+
|
16
18
|
## Install as an npm library
|
19
|
+
|
17
20
|
Jackson is available as an [npm package](https://www.npmjs.com/package/@boxyhq/saml-jackson) that can be integrated into Express.js routes. The library should be usable with other node.js web application frameworks but is currently untested. Please file an issue or submit a PR if you encounter any issues.
|
18
|
-
|
21
|
+
|
19
22
|
```
|
20
23
|
npm i @boxyhq/saml-jackson
|
21
24
|
```
|
22
|
-
|
25
|
+
|
23
26
|
### Add Express Routes
|
24
|
-
|
27
|
+
|
25
28
|
```
|
26
29
|
// express
|
27
30
|
const express = require('express');
|
28
31
|
const router = express.Router();
|
29
32
|
const cors = require('cors'); // needed if you are calling the token userinfo endpoints from the frontend
|
30
|
-
|
33
|
+
|
31
34
|
// Set the required options. Refer to https://github.com/boxyhq/jackson#configuration for the full list
|
32
35
|
const opts = {
|
33
36
|
externalUrl: 'https://my-cool-app.com',
|
@@ -36,9 +39,9 @@ const opts = {
|
|
36
39
|
db: {
|
37
40
|
engine: 'mongo',
|
38
41
|
url: 'mongodb://localhost:27017/my-cool-app',
|
39
|
-
}
|
42
|
+
}
|
40
43
|
};
|
41
|
-
|
44
|
+
|
42
45
|
|
43
46
|
let apiController;
|
44
47
|
let oauthController;
|
@@ -49,17 +52,17 @@ async function init() {
|
|
49
52
|
apiController = ret.apiController;
|
50
53
|
oauthController = ret.oauthController;
|
51
54
|
}
|
52
|
-
|
55
|
+
|
53
56
|
// express.js middlewares needed to parse json and x-www-form-urlencoded
|
54
57
|
router.use(express.json());
|
55
58
|
router.use(express.urlencoded({ extended: true }));
|
56
|
-
|
59
|
+
|
57
60
|
// SAML config API. You should pass this route through your authentication checks, do not expose this on the public interface without proper authentication in place.
|
58
61
|
router.post('/api/v1/saml/config', async (req, res) => {
|
59
62
|
try {
|
60
63
|
// apply your authentication flow (or ensure this route has passed through your auth middleware)
|
61
64
|
...
|
62
|
-
|
65
|
+
|
63
66
|
// only when properly authenticated, call the config function
|
64
67
|
res.json(await apiController.config(req.body));
|
65
68
|
} catch (err) {
|
@@ -68,7 +71,7 @@ router.post('/api/v1/saml/config', async (req, res) => {
|
|
68
71
|
});
|
69
72
|
}
|
70
73
|
});
|
71
|
-
|
74
|
+
|
72
75
|
// OAuth 2.0 flow
|
73
76
|
router.get('/oauth/authorize', async (req, res) => {
|
74
77
|
try {
|
@@ -77,7 +80,7 @@ router.get('/oauth/authorize', async (req, res) => {
|
|
77
80
|
res.status(500).send(err.message);
|
78
81
|
}
|
79
82
|
});
|
80
|
-
|
83
|
+
|
81
84
|
router.post('/oauth/saml', async (req, res) => {
|
82
85
|
try {
|
83
86
|
await oauthController.samlResponse(req, res);
|
@@ -85,7 +88,7 @@ router.post('/oauth/saml', async (req, res) => {
|
|
85
88
|
res.status(500).send(err.message);
|
86
89
|
}
|
87
90
|
});
|
88
|
-
|
91
|
+
|
89
92
|
router.post('/oauth/token', cors(), async (req, res) => {
|
90
93
|
try {
|
91
94
|
await oauthController.token(req, res);
|
@@ -93,7 +96,7 @@ router.post('/oauth/token', cors(), async (req, res) => {
|
|
93
96
|
res.status(500).send(err.message);
|
94
97
|
}
|
95
98
|
});
|
96
|
-
|
99
|
+
|
97
100
|
router.get('/oauth/userinfo', cors(), async (req, res) => {
|
98
101
|
try {
|
99
102
|
await oauthController.userInfo(req, res);
|
@@ -101,15 +104,16 @@ router.get('/oauth/userinfo', cors(), async (req, res) => {
|
|
101
104
|
res.status(500).send(err.message);
|
102
105
|
}
|
103
106
|
});
|
104
|
-
|
107
|
+
|
105
108
|
// set the router
|
106
109
|
app.use('/sso', router);
|
107
|
-
|
110
|
+
|
108
111
|
```
|
109
|
-
|
112
|
+
|
110
113
|
## Deployment as a service: Docker
|
114
|
+
|
111
115
|
The docker container can be found at [boxyhq/jackson](https://hub.docker.com/r/boxyhq/jackson/tags). It is preferable to use a specific version instead of the `latest` tag. Jackson uses two ports (configurable if needed, see below) 5000 and 6000. 6000 is the internal port and ideally should not be exposed to a public network.
|
112
|
-
|
116
|
+
|
113
117
|
```
|
114
118
|
docker run -p 5000:5000 -p 6000:6000 boxyhq/jackson:78e9099d
|
115
119
|
```
|
@@ -119,17 +123,19 @@ Refer to https://github.com/boxyhq/jackson#configuration for the full configurat
|
|
119
123
|
Kubernetes and docker-compose deployment files will be coming soon.
|
120
124
|
|
121
125
|
## Usage
|
122
|
-
|
126
|
+
|
123
127
|
### 1. Setting up SAML with your customer's Identity Provider
|
128
|
+
|
124
129
|
Please follow the instructions [here](https://docs.google.com/document/d/1fk---Z9Ln59u-2toGKUkyO3BF6Dh3dscT2u4J2xHANE) to guide your customers in setting up SAML correctly for your product(s). You should create a copy of the doc and modify it with your custom settings, we have used the values that work for our demo apps.
|
125
|
-
|
130
|
+
|
126
131
|
### 2. SAML config API
|
132
|
+
|
127
133
|
Once your customer has set up the SAML app on their Identity Provider, the Identity Provider will generate an IdP or SP metadata file. Some Identity Providers only generate an IdP metadata file but it usually works for the SP login flow as well. It is an XML file that contains various attributes Jackson needs to validate incoming SAML login requests. This step is the equivalent of setting an OAuth 2.0 app and generating a client ID and client secret that will be used in the login flow.
|
128
|
-
|
134
|
+
|
129
135
|
You will need to provide a place in the UI for your customers (The account settings page is usually a good place for this) to configure this and then call the API below.
|
130
|
-
|
136
|
+
|
131
137
|
The following API call sets up the configuration in Jackson:
|
132
|
-
|
138
|
+
|
133
139
|
```
|
134
140
|
curl --location --request POST 'http://localhost:6000/api/v1/saml/config' \
|
135
141
|
--header 'Content-Type: application/x-www-form-urlencoded' \
|
@@ -139,24 +145,27 @@ curl --location --request POST 'http://localhost:6000/api/v1/saml/config' \
|
|
139
145
|
--data-urlencode 'tenant=boxyhq.com' \
|
140
146
|
--data-urlencode 'product=demo'
|
141
147
|
```
|
142
|
-
|
148
|
+
|
143
149
|
- rawMetadata: The XML metadata file your customer gets from their Identity Provider
|
144
150
|
- defaultRedirectUrl: The redirect URL to use in the IdP login flow. Jackson will call this URL after completing an IdP login flow
|
145
151
|
- redirectUrl: JSON encoded array containing a list of allowed redirect URLs. Jackson will disallow any redirects not on this list (or not the default URL above)
|
146
152
|
- tenant: Jackson supports a multi-tenant architecture, this is a unique identifier you set from your side that relates back to your customer's tenant. This is normally an email, domain, an account id, or user-id
|
147
153
|
- product: Jackson support multiple products, this is a unique identifier you set from your side that relates back to the product your customer is using
|
148
|
-
|
149
|
-
The response returns a JSON with `client_id` and `client_secret` that can be stored against your tenant and product for a more secure OAuth 2.0 flow. If you do not want to store the `client_id` and `client_secret` you can alternatively use `client_id=
|
150
|
-
|
154
|
+
|
155
|
+
The response returns a JSON with `client_id` and `client_secret` that can be stored against your tenant and product for a more secure OAuth 2.0 flow. If you do not want to store the `client_id` and `client_secret` you can alternatively use `client_id=tenant=<tenantID>&product=<productID>` and any arbitrary value for `client_secret` when setting up the OAuth 2.0 flow.
|
156
|
+
|
151
157
|
### 3. OAuth 2.0 Flow
|
158
|
+
|
152
159
|
Jackson has been designed to abstract the SAML login flow as a pure OAuth 2.0 flow. This means it's compatible with any standard OAuth 2.0 library out there, both client-side and server-side. It is important to remember that SAML is configured per customer unlike OAuth 2.0 where you can have a single OAuth app supporting logins for all customers.
|
153
|
-
|
160
|
+
|
154
161
|
Jackson also supports the PKCE authorization flow (https://oauth.net/2/pkce/), so you can protect your SPAs.
|
155
|
-
|
162
|
+
|
156
163
|
If for any reason you need to implement the flow on your own, the steps are outlined below:
|
157
|
-
|
164
|
+
|
158
165
|
### 4. Authorize
|
166
|
+
|
159
167
|
The OAuth flow begins with redirecting your user to the `authorize` URL:
|
168
|
+
|
160
169
|
```
|
161
170
|
https://localhost:5000/oauth/authorize
|
162
171
|
?response_type=code&provider=saml
|
@@ -164,16 +173,18 @@ https://localhost:5000/oauth/authorize
|
|
164
173
|
&redirect_uri=<redirect URL>
|
165
174
|
&state=<randomly generated state id>
|
166
175
|
```
|
167
|
-
|
176
|
+
|
168
177
|
- response_type=code: This is the only supported type for now but maybe extended in the future
|
169
|
-
- client_id: Use the client_id returned by the SAML config API or use `
|
178
|
+
- client_id: Use the client_id returned by the SAML config API or use `tenant=<tenantID>&product=<productID>` to use the tenant and product IDs instead. **Note:** Please don't forget to URL encode the query parameters including `client_id`.
|
170
179
|
- redirect_uri: This is where the user will be taken back once the authorization flow is complete
|
171
180
|
- state: Use a randomly generated string as the state, this will be echoed back as a query parameter when taking the user back to the `redirect_uri` above. You should validate the state to prevent XSRF attacks
|
172
|
-
|
181
|
+
|
173
182
|
### 5. Code Exchange
|
183
|
+
|
174
184
|
After successful authorization, the user is redirected back to the `redirect_uri`. The query parameters will include the `code` and `state` parameters. You should validate that the state matches the one you sent in the `authorize` request.
|
175
|
-
|
185
|
+
|
176
186
|
The code can then be exchanged for a token by making the following request:
|
187
|
+
|
177
188
|
```
|
178
189
|
curl --request POST \
|
179
190
|
--url 'http://localhost:5000/oauth/token' \
|
@@ -184,12 +195,14 @@ curl --request POST \
|
|
184
195
|
--data 'redirect_uri=<redirect URL>' \
|
185
196
|
--data code=<code from the query parameter above>
|
186
197
|
```
|
198
|
+
|
187
199
|
- grant_type=authorization_code: This is the only supported flow, for now. We might extend this in the future
|
188
|
-
- client_id: Use the client_id returned by the SAML config API or use `
|
200
|
+
- client_id: Use the client_id returned by the SAML config API or use `tenant=<tenantID>&product=<productID>` to use the tenant and product IDs instead. **Note:** Please don't forget to URL encode the query parameters including `client_id`.
|
189
201
|
- client_secret: Use the client_secret returned by the SAML config API or any arbitrary value if using the tenant and product in the clientID
|
190
202
|
- redirect_uri: This is where the user will be taken back once the authorization flow is complete. Use the same redirect_uri as the previous request
|
191
|
-
|
203
|
+
|
192
204
|
If everything goes well you should receive a JSON response that includes the access token. This token is needed for the next step where we fetch the user profile.
|
205
|
+
|
193
206
|
```
|
194
207
|
{
|
195
208
|
"access_token": <access token>,
|
@@ -197,17 +210,20 @@ If everything goes well you should receive a JSON response that includes the acc
|
|
197
210
|
"expires_in": 300
|
198
211
|
}
|
199
212
|
```
|
200
|
-
|
213
|
+
|
201
214
|
### 6. Profile Request
|
215
|
+
|
202
216
|
The short-lived access token can now be used to request the user's profile. You'll need to make the following request:
|
217
|
+
|
203
218
|
```
|
204
219
|
curl --request GET \
|
205
220
|
--url https://localhost:5000/oauth/me \
|
206
221
|
--header 'authorization: Bearer <access token>' \
|
207
222
|
--header 'content-type: application/json'
|
208
223
|
```
|
209
|
-
|
224
|
+
|
210
225
|
If everything goes well you should receive a JSON response with the user's profile:
|
226
|
+
|
211
227
|
```
|
212
228
|
{
|
213
229
|
"email": "sjackson@coolstartup.com",
|
@@ -216,53 +232,60 @@ If everything goes well you should receive a JSON response with the user's profi
|
|
216
232
|
"lastName": "Jackson",
|
217
233
|
}
|
218
234
|
```
|
219
|
-
|
235
|
+
|
220
236
|
- email: The email address of the user as provided by the Identity Provider
|
221
237
|
- id: The id of the user as provided by the Identity Provider
|
222
238
|
- firstName: The first name of the user as provided by the Identity Provider
|
223
239
|
- lastName: The last name of the user as provided by the Identity Provider
|
224
|
-
|
240
|
+
|
225
241
|
## Examples
|
242
|
+
|
226
243
|
To Do
|
227
|
-
|
244
|
+
|
228
245
|
## Database Support
|
246
|
+
|
229
247
|
Jackson currently supports the following databases.
|
230
|
-
|
248
|
+
|
231
249
|
- Postgres
|
232
250
|
- CockroachDB
|
233
251
|
- MySQL
|
234
252
|
- MariaDB
|
235
253
|
- MongoDB
|
236
254
|
- Redis
|
237
|
-
|
255
|
+
|
238
256
|
## Configuration
|
257
|
+
|
239
258
|
Configuration is done via env vars (and in the case of the npm library via an options object).
|
240
|
-
|
259
|
+
|
241
260
|
The following options are supported and will have to be configured during deployment.
|
242
|
-
|
261
|
+
|
243
262
|
| Key | Description | Default |
|
244
|
-
|
263
|
+
| --------------------------------- | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | ------------------------------- |
|
245
264
|
| HOST_URL | The URL to bind to | `localhost` |
|
246
265
|
| HOST_PORT | The port to bind to | `5000` |
|
247
266
|
| EXTERNAL_URL (npm: externalUrl) | The public URL to reach this service, used internally for documenting the SAML configuration instructions. | `http://{HOST_URL}:{HOST_PORT}` |
|
248
267
|
| INTERNAL_HOST_URL | The URL to bind to expose the internal APIs. Do not configure this to a public network. | `localhost` |
|
249
268
|
| INTERNAL_HOST_PORT | The port to bind to for the internal APIs. | `6000` |
|
250
|
-
| SAML_AUDIENCE (npm: samlAudience) | This is just an identifier to validate the SAML audience, this value will also get configured in the SAML apps created by your customers.
|
269
|
+
| SAML_AUDIENCE (npm: samlAudience) | This is just an identifier to validate the SAML audience, this value will also get configured in the SAML apps created by your customers. Once set do not change this value unless you get your customers to reconfigure their SAML again. It is case-sensitive. This does not have to be a real URL. | `https://saml.boxyhq.com` |
|
251
270
|
| IDP_ENABLED (npm: idpEnabled) | Set to `true` to enable IdP initiated login for SAML. SP initiated login is the only recommended flow but you might have to support IdP login at times. | `false` |
|
252
271
|
| DB_ENGINE (npm: db.engine) | Supported values are `redis`, `sql`, `mongo`, `mem`. | `sql` |
|
253
272
|
| DB_URL (npm: db.url) | The database URL to connect to. For example `postgres://postgres:postgres@localhost:5450/jackson` | |
|
254
273
|
| DB_TYPE (npm: db.type) | Only needed when DB_ENGINE is `sql`. Supported values are `postgres`, `cockroachdb`, `mysql`, `mariadb`. | `postgres` |
|
255
274
|
| PRE_LOADED_CONFIG | If you only need a single tenant or a handful of pre-configured tenants then this config will help you read and load SAML configs. It works well with the mem DB engine so you don't have to configure any external databases for this to work (though it works with those as well). This is a path (absolute or relative) to a directory that contains files organized in the format described in the next section. | |
|
256
|
-
|
275
|
+
|
257
276
|
## Pre-loaded SAML Configuration
|
277
|
+
|
258
278
|
If PRE_LOADED_CONFIG is set then it should point to a directory with the following structure (example below):-
|
279
|
+
|
259
280
|
```
|
260
281
|
boxyhq.js
|
261
282
|
boxyhq.xml
|
262
283
|
anothertenant.js
|
263
284
|
anothertenant.xml
|
264
285
|
```
|
286
|
+
|
265
287
|
The JS file has the following structure:-
|
288
|
+
|
266
289
|
```
|
267
290
|
module.exports = {
|
268
291
|
defaultRedirectUrl: 'http://localhost:3000/login/saml',
|
@@ -271,29 +294,34 @@ module.exports = {
|
|
271
294
|
product: 'demo',
|
272
295
|
};
|
273
296
|
```
|
297
|
+
|
274
298
|
The XML file (should share the name with the .js file) is the raw XML metadata file you receive from your Identity Provider. Please ensure it is saved in the `utf-8` encoding.
|
275
|
-
|
299
|
+
|
276
300
|
The config and XML above correspond to the `SAML API config` (see below).
|
277
|
-
|
301
|
+
|
278
302
|
## SAML Login flows
|
303
|
+
|
279
304
|
There are two kinds of SAML login flows - SP-initiated and IdP-initiated. We highly recommend sticking to the SP-initiated flow since it is more secure but Jackson also supports the IdP-initiated flow if you enable it. For an in-depth understanding of SAML and the two flows please refer to Okta's comprehensive guide - https://developer.okta.com/docs/concepts/saml/.
|
280
|
-
|
305
|
+
|
281
306
|
## Contributing
|
307
|
+
|
282
308
|
Thanks for taking the time to contribute! Contributions are what make the open-source community such an amazing place to learn, inspire, and create. Any contributions you make will benefit everybody else and are appreciated.
|
283
|
-
|
309
|
+
|
284
310
|
Please try to create bug reports that are:
|
285
|
-
|
311
|
+
|
286
312
|
- _Reproducible._ Include steps to reproduce the problem.
|
287
313
|
- _Specific._ Include as much detail as possible: which version, what environment, etc.
|
288
314
|
- _Unique._ Do not duplicate existing opened issues.
|
289
315
|
- _Scoped to a Single Bug._ One bug per report.
|
290
|
-
|
316
|
+
|
291
317
|
## Support
|
318
|
+
|
292
319
|
Reach out to the maintainer at one of the following places:
|
293
320
|
|
294
321
|
- [GitHub Discussions](https://github.com/boxyhq/jackson/discussions)
|
295
322
|
- [GitHub Issues](https://github.com/boxyhq/jackson/issues)
|
296
323
|
- The email which is located [in GitHub profile](https://github.com/deepakprabhakara)
|
297
|
-
|
324
|
+
|
298
325
|
## License
|
326
|
+
|
299
327
|
[Apache 2.0 License](https://github.com/boxyhq/jackson/blob/main/LICENSE)
|
package/package.json
CHANGED
package/src/controller/oauth.js
CHANGED
@@ -2,7 +2,7 @@ const crypto = require('crypto');
|
|
2
2
|
|
3
3
|
const saml = require('../saml/saml.js');
|
4
4
|
const codeVerifier = require('./oauth/code-verifier.js');
|
5
|
-
const { indexNames } = require('./utils.js');
|
5
|
+
const { indexNames, extractAuthToken } = require('./utils.js');
|
6
6
|
const dbutils = require('../db/utils.js');
|
7
7
|
const redirect = require('./oauth/redirect.js');
|
8
8
|
const allowed = require('./oauth/allowed.js');
|
@@ -15,16 +15,6 @@ let options;
|
|
15
15
|
|
16
16
|
const relayStatePrefix = 'boxyhq_jackson_';
|
17
17
|
|
18
|
-
const extractBearerToken = (req) => {
|
19
|
-
const authHeader = req.get('authorization');
|
20
|
-
const parts = (authHeader || '').split(' ');
|
21
|
-
if (parts.length > 1) {
|
22
|
-
return parts[1];
|
23
|
-
}
|
24
|
-
|
25
|
-
return null;
|
26
|
-
};
|
27
|
-
|
28
18
|
function getEncodedClientId(client_id) {
|
29
19
|
try {
|
30
20
|
const sp = new URLSearchParams(client_id);
|
@@ -303,7 +293,7 @@ const token = async (req, res) => {
|
|
303
293
|
};
|
304
294
|
|
305
295
|
const userInfo = async (req, res) => {
|
306
|
-
let token =
|
296
|
+
let token = extractAuthToken(req);
|
307
297
|
|
308
298
|
// check for query param
|
309
299
|
if (!token) {
|
package/src/controller/utils.js
CHANGED
@@ -3,6 +3,17 @@ const indexNames = {
|
|
3
3
|
tenantProduct: 'tenantProduct',
|
4
4
|
};
|
5
5
|
|
6
|
+
const extractAuthToken = (req) => {
|
7
|
+
const authHeader = req.get('authorization');
|
8
|
+
const parts = (authHeader || '').split(' ');
|
9
|
+
if (parts.length > 1) {
|
10
|
+
return parts[1];
|
11
|
+
}
|
12
|
+
|
13
|
+
return null;
|
14
|
+
};
|
15
|
+
|
6
16
|
module.exports = {
|
7
17
|
indexNames,
|
18
|
+
extractAuthToken,
|
8
19
|
};
|
package/src/env.js
CHANGED
@@ -7,6 +7,8 @@ const samlPath = process.env.SAML_PATH || '/oauth/saml';
|
|
7
7
|
const internalHostUrl = process.env.INTERNAL_HOST_URL || 'localhost';
|
8
8
|
const internalHostPort = (process.env.INTERNAL_HOST_PORT || '6000') * 1;
|
9
9
|
|
10
|
+
const apiKeys = (process.env.JACKSON_API_KEYS || '').split(',');
|
11
|
+
|
10
12
|
const samlAudience = process.env.SAML_AUDIENCE;
|
11
13
|
const preLoadedConfig = process.env.PRE_LOADED_CONFIG;
|
12
14
|
|
@@ -27,6 +29,7 @@ module.exports = {
|
|
27
29
|
preLoadedConfig,
|
28
30
|
internalHostUrl,
|
29
31
|
internalHostPort,
|
32
|
+
apiKeys,
|
30
33
|
idpEnabled,
|
31
34
|
db,
|
32
35
|
useInternalServer: !(
|
package/src/jackson.js
CHANGED
@@ -2,6 +2,7 @@ const express = require('express');
|
|
2
2
|
const cors = require('cors');
|
3
3
|
|
4
4
|
const env = require('./env.js');
|
5
|
+
const { extractAuthToken } = require('./controller/utils.js');
|
5
6
|
|
6
7
|
let apiController;
|
7
8
|
let oauthController;
|
@@ -66,8 +67,18 @@ if (env.useInternalServer) {
|
|
66
67
|
internalApp.use(express.urlencoded({ extended: true }));
|
67
68
|
}
|
68
69
|
|
70
|
+
const validateApiKey = (token) => {
|
71
|
+
return env.apiKeys.includes(token);
|
72
|
+
};
|
73
|
+
|
69
74
|
internalApp.post(apiPath + '/config', async (req, res) => {
|
70
75
|
try {
|
76
|
+
const apiKey = extractAuthToken(req);
|
77
|
+
if (!validateApiKey(apiKey)) {
|
78
|
+
res.status(401).send('Unauthorized');
|
79
|
+
return;
|
80
|
+
}
|
81
|
+
|
71
82
|
res.json(await apiController.config(req.body));
|
72
83
|
} catch (err) {
|
73
84
|
res.status(500).json({
|