@optimizely-opal/opal-tool-ocp-sdk 1.0.0-beta.1 โ 1.0.0-beta.10
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 +169 -3
- package/dist/auth/AuthUtils.d.ts +12 -5
- package/dist/auth/AuthUtils.d.ts.map +1 -1
- package/dist/auth/AuthUtils.js +80 -25
- package/dist/auth/AuthUtils.js.map +1 -1
- package/dist/auth/AuthUtils.test.js +161 -117
- package/dist/auth/AuthUtils.test.js.map +1 -1
- package/dist/function/GlobalToolFunction.d.ts +5 -3
- package/dist/function/GlobalToolFunction.d.ts.map +1 -1
- package/dist/function/GlobalToolFunction.js +32 -8
- package/dist/function/GlobalToolFunction.js.map +1 -1
- package/dist/function/GlobalToolFunction.test.js +73 -12
- package/dist/function/GlobalToolFunction.test.js.map +1 -1
- package/dist/function/ToolFunction.d.ts +11 -4
- package/dist/function/ToolFunction.d.ts.map +1 -1
- package/dist/function/ToolFunction.js +45 -9
- package/dist/function/ToolFunction.js.map +1 -1
- package/dist/function/ToolFunction.test.js +278 -11
- package/dist/function/ToolFunction.test.js.map +1 -1
- package/dist/index.d.ts +2 -1
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +3 -1
- package/dist/index.js.map +1 -1
- package/dist/logging/ToolLogger.d.ts +42 -0
- package/dist/logging/ToolLogger.d.ts.map +1 -0
- package/dist/logging/ToolLogger.js +255 -0
- package/dist/logging/ToolLogger.js.map +1 -0
- package/dist/logging/ToolLogger.test.d.ts +2 -0
- package/dist/logging/ToolLogger.test.d.ts.map +1 -0
- package/dist/logging/ToolLogger.test.js +864 -0
- package/dist/logging/ToolLogger.test.js.map +1 -0
- package/dist/service/Service.d.ts +88 -2
- package/dist/service/Service.d.ts.map +1 -1
- package/dist/service/Service.js +228 -39
- package/dist/service/Service.js.map +1 -1
- package/dist/service/Service.test.js +558 -22
- package/dist/service/Service.test.js.map +1 -1
- package/dist/types/Models.d.ts +7 -1
- package/dist/types/Models.d.ts.map +1 -1
- package/dist/types/Models.js +5 -1
- package/dist/types/Models.js.map +1 -1
- package/dist/types/ToolError.d.ts +72 -0
- package/dist/types/ToolError.d.ts.map +1 -0
- package/dist/types/ToolError.js +107 -0
- package/dist/types/ToolError.js.map +1 -0
- package/dist/types/ToolError.test.d.ts +2 -0
- package/dist/types/ToolError.test.d.ts.map +1 -0
- package/dist/types/ToolError.test.js +185 -0
- package/dist/types/ToolError.test.js.map +1 -0
- package/dist/validation/ParameterValidator.d.ts +31 -0
- package/dist/validation/ParameterValidator.d.ts.map +1 -0
- package/dist/validation/ParameterValidator.js +129 -0
- package/dist/validation/ParameterValidator.js.map +1 -0
- package/dist/validation/ParameterValidator.test.d.ts +2 -0
- package/dist/validation/ParameterValidator.test.d.ts.map +1 -0
- package/dist/validation/ParameterValidator.test.js +323 -0
- package/dist/validation/ParameterValidator.test.js.map +1 -0
- package/package.json +3 -3
- package/src/auth/AuthUtils.test.ts +176 -157
- package/src/auth/AuthUtils.ts +96 -33
- package/src/function/GlobalToolFunction.test.ts +78 -14
- package/src/function/GlobalToolFunction.ts +46 -11
- package/src/function/ToolFunction.test.ts +298 -13
- package/src/function/ToolFunction.ts +61 -13
- package/src/index.ts +2 -1
- package/src/logging/ToolLogger.test.ts +1020 -0
- package/src/logging/ToolLogger.ts +292 -0
- package/src/service/Service.test.ts +712 -28
- package/src/service/Service.ts +288 -38
- package/src/types/Models.ts +8 -1
- package/src/types/ToolError.test.ts +222 -0
- package/src/types/ToolError.ts +125 -0
- package/src/validation/ParameterValidator.test.ts +371 -0
- package/src/validation/ParameterValidator.ts +150 -0
package/README.md
CHANGED
|
@@ -13,6 +13,7 @@ A TypeScript SDK for building Opal tools in Optimizely Connect Platform. This SD
|
|
|
13
13
|
- ๐ **Authentication Support** - OptiID authentication
|
|
14
14
|
- ๐ก๏ธ **Authorization Support** - OptiID token tool authorization
|
|
15
15
|
- ๐ **Parameter Validation** - Define and validate tool parameters with types
|
|
16
|
+
- โ
**Automatic Validation** - SDK automatically validates parameters and returns RFC 9457 compliant error responses
|
|
16
17
|
- ๐งช **Comprehensive Testing** - Fully tested with Jest
|
|
17
18
|
|
|
18
19
|
## Installation
|
|
@@ -223,6 +224,47 @@ enum ParameterType {
|
|
|
223
224
|
}
|
|
224
225
|
```
|
|
225
226
|
|
|
227
|
+
### Parameter Validation
|
|
228
|
+
|
|
229
|
+
The SDK automatically validates all incoming parameters against the parameter definitions you specify for your tools. When Opal sends requests to your tools, the SDK performs validation before calling your handler methods:
|
|
230
|
+
|
|
231
|
+
#### Automatic Validation Features
|
|
232
|
+
|
|
233
|
+
- **Type Checking**: Ensures parameters match their defined types (string, integer, number, boolean, list, object)
|
|
234
|
+
- **Required Validation**: Verifies that all required parameters are present and not null/undefined
|
|
235
|
+
- **Early Error Response**: Returns validation errors immediately without calling your handler if validation fails
|
|
236
|
+
- **RFC 9457 Compliance**: Error responses follow the RFC 9457 Problem Details for HTTP APIs specification
|
|
237
|
+
|
|
238
|
+
#### Validation Error Response Format
|
|
239
|
+
|
|
240
|
+
When parameter validation fails, the SDK returns a standardized error response with HTTP status 400 and `Content-Type: application/problem+json`:
|
|
241
|
+
|
|
242
|
+
```json
|
|
243
|
+
{
|
|
244
|
+
"title": "One or more validation errors occurred.",
|
|
245
|
+
"status": 400,
|
|
246
|
+
"detail": "See 'errors' field for details.",
|
|
247
|
+
"instance": "/your-tool-endpoint",
|
|
248
|
+
"errors": [
|
|
249
|
+
{
|
|
250
|
+
"field": "title",
|
|
251
|
+
"message": "Parameter 'title' must be a string, but received number"
|
|
252
|
+
},
|
|
253
|
+
{
|
|
254
|
+
"field": "priority",
|
|
255
|
+
"message": "Required parameter 'priority' is missing"
|
|
256
|
+
}
|
|
257
|
+
]
|
|
258
|
+
}
|
|
259
|
+
```
|
|
260
|
+
|
|
261
|
+
**Benefits:**
|
|
262
|
+
|
|
263
|
+
- **Reduced Boilerplate**: No need to write parameter validation code in your handlers
|
|
264
|
+
- **Consistent Error Format**: All validation errors follow the same RFC 9457 standard format
|
|
265
|
+
- **Better Developer Experience**: Clear, actionable error messages for API consumers
|
|
266
|
+
- **Type Safety**: Validation ensures your handlers receive correctly typed parameters
|
|
267
|
+
|
|
226
268
|
### Authentication
|
|
227
269
|
|
|
228
270
|
The SDK supports authentication and authorization mechanisms:
|
|
@@ -275,6 +317,119 @@ export class MyToolFunction extends ToolFunction {
|
|
|
275
317
|
}
|
|
276
318
|
```
|
|
277
319
|
|
|
320
|
+
## Error Handling
|
|
321
|
+
|
|
322
|
+
The SDK provides RFC 9457 Problem Details compliant error handling through the `ToolError` class. This allows you to throw errors with custom HTTP status codes and detailed error information.
|
|
323
|
+
|
|
324
|
+
### ToolError Class
|
|
325
|
+
|
|
326
|
+
```typescript
|
|
327
|
+
class ToolError extends Error {
|
|
328
|
+
constructor(
|
|
329
|
+
message: string, // Error message (used as "title" in RFC 9457)
|
|
330
|
+
status?: number, // HTTP status code (default: 500)
|
|
331
|
+
detail?: string // Detailed error description (optional)
|
|
332
|
+
)
|
|
333
|
+
}
|
|
334
|
+
```
|
|
335
|
+
|
|
336
|
+
### Usage Examples
|
|
337
|
+
|
|
338
|
+
```typescript
|
|
339
|
+
import { ToolFunction, tool, ToolError, ParameterType } from '@optimizely-opal/opal-tool-ocp-sdk';
|
|
340
|
+
|
|
341
|
+
|
|
342
|
+
// Throw a 404 error
|
|
343
|
+
throw new ToolError(
|
|
344
|
+
'Task not found',
|
|
345
|
+
404,
|
|
346
|
+
`No task exists with ID: ${params.taskId}`
|
|
347
|
+
);
|
|
348
|
+
|
|
349
|
+
// Throw a 400 error for invalid input
|
|
350
|
+
throw new ToolError(
|
|
351
|
+
'Invalid priority',
|
|
352
|
+
400,
|
|
353
|
+
`Priority must be one of: ${validPriorities.join(', ')}`
|
|
354
|
+
);
|
|
355
|
+
```
|
|
356
|
+
|
|
357
|
+
### Error Response Format
|
|
358
|
+
|
|
359
|
+
When a `ToolError` is thrown, the SDK automatically formats it as an RFC 9457 Problem Details response:
|
|
360
|
+
|
|
361
|
+
```json
|
|
362
|
+
{
|
|
363
|
+
"title": "Task not found",
|
|
364
|
+
"status": 404,
|
|
365
|
+
"detail": "No task exists with ID: task-123",
|
|
366
|
+
"instance": "/get-task"
|
|
367
|
+
}
|
|
368
|
+
```
|
|
369
|
+
|
|
370
|
+
### Validation Errors with Multiple Fields
|
|
371
|
+
|
|
372
|
+
You can also throw `ToolError` with an `errors` array for validation scenarios with multiple field errors:
|
|
373
|
+
|
|
374
|
+
```typescript
|
|
375
|
+
import { ToolError } from '@optimizely-opal/opal-tool-ocp-sdk';
|
|
376
|
+
|
|
377
|
+
// Validate multiple fields
|
|
378
|
+
const validationErrors = [];
|
|
379
|
+
|
|
380
|
+
if (!email.includes('@')) {
|
|
381
|
+
validationErrors.push({
|
|
382
|
+
field: 'email',
|
|
383
|
+
message: 'Invalid email format'
|
|
384
|
+
});
|
|
385
|
+
}
|
|
386
|
+
|
|
387
|
+
if (age < 0) {
|
|
388
|
+
validationErrors.push({
|
|
389
|
+
field: 'age',
|
|
390
|
+
message: 'Age must be a positive number'
|
|
391
|
+
});
|
|
392
|
+
}
|
|
393
|
+
|
|
394
|
+
if (validationErrors.length > 0) {
|
|
395
|
+
throw new ToolError(
|
|
396
|
+
'Validation failed',
|
|
397
|
+
400,
|
|
398
|
+
"See 'errors' field for details.",
|
|
399
|
+
validationErrors
|
|
400
|
+
);
|
|
401
|
+
}
|
|
402
|
+
```
|
|
403
|
+
|
|
404
|
+
This will return:
|
|
405
|
+
|
|
406
|
+
```json
|
|
407
|
+
{
|
|
408
|
+
"title": "Validation failed",
|
|
409
|
+
"status": 400,
|
|
410
|
+
"detail": "See 'errors' field for details.",
|
|
411
|
+
"instance": "/create-user",
|
|
412
|
+
"errors": [
|
|
413
|
+
{
|
|
414
|
+
"field": "email",
|
|
415
|
+
"message": "Invalid email format"
|
|
416
|
+
},
|
|
417
|
+
{
|
|
418
|
+
"field": "age",
|
|
419
|
+
"message": "Age must be a positive number"
|
|
420
|
+
}
|
|
421
|
+
]
|
|
422
|
+
}
|
|
423
|
+
```
|
|
424
|
+
|
|
425
|
+
**Response Headers:**
|
|
426
|
+
- `Content-Type: application/problem+json`
|
|
427
|
+
- HTTP status code matches the `ToolError` status
|
|
428
|
+
|
|
429
|
+
**Note:**
|
|
430
|
+
- If a regular `Error` (not `ToolError`) is thrown, it will be automatically wrapped in a 500 response with RFC 9457 format
|
|
431
|
+
- Parameter validation is automatic and uses this same format when validation fails
|
|
432
|
+
|
|
278
433
|
## API Reference
|
|
279
434
|
|
|
280
435
|
### Handler Function Signatures
|
|
@@ -327,7 +482,7 @@ Abstract base class for organization-scoped OCP functions:
|
|
|
327
482
|
|
|
328
483
|
```typescript
|
|
329
484
|
export abstract class ToolFunction extends Function {
|
|
330
|
-
protected ready(): Promise<
|
|
485
|
+
protected ready(): Promise<ReadyResponse>;
|
|
331
486
|
public async perform(): Promise<Response>;
|
|
332
487
|
}
|
|
333
488
|
```
|
|
@@ -340,7 +495,7 @@ Abstract base class for global OCP functions:
|
|
|
340
495
|
|
|
341
496
|
```typescript
|
|
342
497
|
export abstract class GlobalToolFunction extends GlobalFunction {
|
|
343
|
-
protected ready(): Promise<
|
|
498
|
+
protected ready(): Promise<ReadyResponse>;
|
|
344
499
|
public async perform(): Promise<Response>;
|
|
345
500
|
}
|
|
346
501
|
```
|
|
@@ -357,6 +512,8 @@ Key model classes with generic type support:
|
|
|
357
512
|
- `AuthRequirement` - Defines authentication needs
|
|
358
513
|
- `InteractionResult` - Response from interactions
|
|
359
514
|
- `OptiIdAuthData` - OptiID specific authentication data
|
|
515
|
+
- `ReadyResponse` - Response type for the ready method containing status and optional reason
|
|
516
|
+
- `ToolError` - Custom error class for RFC 9457 Problem Details error responses with configurable HTTP status codes
|
|
360
517
|
|
|
361
518
|
## Discovery and Ready Endpoints
|
|
362
519
|
|
|
@@ -431,9 +588,18 @@ Returns the current readiness status of your function:
|
|
|
431
588
|
}
|
|
432
589
|
```
|
|
433
590
|
|
|
591
|
+
Or when not ready with a reason:
|
|
592
|
+
|
|
593
|
+
```json
|
|
594
|
+
{
|
|
595
|
+
"ready": false,
|
|
596
|
+
"reason": "Missing API key"
|
|
597
|
+
}
|
|
598
|
+
```
|
|
599
|
+
|
|
434
600
|
This endpoint calls your function's `ready()` method and returns:
|
|
435
601
|
- `{ready: true}` when the function is ready to process requests
|
|
436
|
-
- `{ready: false}` when the function is not ready (missing configuration, external services unavailable, etc.)
|
|
602
|
+
- `{ready: false, reason?: string}` when the function is not ready (missing configuration, external services unavailable, etc.), optionally with a descriptive reason
|
|
437
603
|
- HTTP 200 status code regardless of ready state (the ready status is in the response body)
|
|
438
604
|
|
|
439
605
|
## Development
|
package/dist/auth/AuthUtils.d.ts
CHANGED
|
@@ -1,26 +1,33 @@
|
|
|
1
|
+
import { Request } from '@zaiusinc/app-sdk';
|
|
1
2
|
import { OptiIdAuthData } from '../types/Models';
|
|
2
3
|
/**
|
|
3
4
|
* Extract and validate basic OptiID authentication data from request
|
|
4
5
|
*
|
|
5
6
|
* @param request - The incoming request
|
|
6
|
-
* @returns object with authData and accessToken, or null if
|
|
7
|
+
* @returns object with authData and accessToken, or null if auth is missing
|
|
7
8
|
*/
|
|
8
9
|
export declare function extractAuthData(request: any): {
|
|
9
10
|
authData: OptiIdAuthData;
|
|
10
11
|
accessToken: string;
|
|
11
12
|
} | null;
|
|
13
|
+
/**
|
|
14
|
+
* Authenticate internal requests using OptiID token from headers
|
|
15
|
+
* @param request The request object
|
|
16
|
+
* @returns true if authentication succeeds
|
|
17
|
+
*/
|
|
18
|
+
export declare function authenticateInternalRequest(request: Request): Promise<void>;
|
|
12
19
|
/**
|
|
13
20
|
* Authenticate a request for regular functions (with organization validation)
|
|
14
21
|
*
|
|
15
22
|
* @param request - The incoming request
|
|
16
|
-
* @
|
|
23
|
+
* @throws {ToolError} If authentication or authorization fails
|
|
17
24
|
*/
|
|
18
|
-
export declare function authenticateRegularRequest(request: any): Promise<
|
|
25
|
+
export declare function authenticateRegularRequest(request: any): Promise<void>;
|
|
19
26
|
/**
|
|
20
27
|
* Authenticate a request for global functions (without organization validation)
|
|
21
28
|
*
|
|
22
29
|
* @param request - The incoming request
|
|
23
|
-
* @
|
|
30
|
+
* @throws {ToolError} If authentication fails
|
|
24
31
|
*/
|
|
25
|
-
export declare function authenticateGlobalRequest(request: any): Promise<
|
|
32
|
+
export declare function authenticateGlobalRequest(request: any): Promise<void>;
|
|
26
33
|
//# sourceMappingURL=AuthUtils.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"AuthUtils.d.ts","sourceRoot":"","sources":["../../src/auth/AuthUtils.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"AuthUtils.d.ts","sourceRoot":"","sources":["../../src/auth/AuthUtils.ts"],"names":[],"mappings":"AAAA,OAAO,EAAyB,OAAO,EAAE,MAAM,mBAAmB,CAAC;AAEnE,OAAO,EAAE,cAAc,EAAE,MAAM,iBAAiB,CAAC;AA4BjD;;;;;GAKG;AACH,wBAAgB,eAAe,CAAC,OAAO,EAAE,GAAG,GAAG;IAAE,QAAQ,EAAE,cAAc,CAAC;IAAC,WAAW,EAAE,MAAM,CAAA;CAAE,GAAG,IAAI,CAiBtG;AA+ED;;;;GAIG;AACH,wBAAsB,2BAA2B,CAAC,OAAO,EAAE,OAAO,GAAG,OAAO,CAAC,IAAI,CAAC,CAsBjF;AAED;;;;;GAKG;AACH,wBAAsB,0BAA0B,CAAC,OAAO,EAAE,GAAG,GAAG,OAAO,CAAC,IAAI,CAAC,CAE5E;AAED;;;;;GAKG;AACH,wBAAsB,yBAAyB,CAAC,OAAO,EAAE,GAAG,GAAG,OAAO,CAAC,IAAI,CAAC,CAE3E"}
|
package/dist/auth/AuthUtils.js
CHANGED
|
@@ -1,60 +1,94 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
3
|
exports.extractAuthData = extractAuthData;
|
|
4
|
+
exports.authenticateInternalRequest = authenticateInternalRequest;
|
|
4
5
|
exports.authenticateRegularRequest = authenticateRegularRequest;
|
|
5
6
|
exports.authenticateGlobalRequest = authenticateGlobalRequest;
|
|
6
7
|
const app_sdk_1 = require("@zaiusinc/app-sdk");
|
|
7
8
|
const TokenVerifier_1 = require("./TokenVerifier");
|
|
9
|
+
const ToolError_1 = require("../types/ToolError");
|
|
8
10
|
/**
|
|
9
11
|
* Validate the OptiID access token
|
|
10
12
|
*
|
|
11
13
|
* @param accessToken - The access token to validate
|
|
12
|
-
* @
|
|
14
|
+
* @throws {ToolError} If token validation fails
|
|
13
15
|
*/
|
|
14
16
|
async function validateAccessToken(accessToken) {
|
|
15
17
|
try {
|
|
16
18
|
if (!accessToken) {
|
|
17
|
-
|
|
19
|
+
throw new ToolError_1.ToolError('Forbidden', 403, 'OptiID access token is required');
|
|
18
20
|
}
|
|
19
21
|
const tokenVerifier = await (0, TokenVerifier_1.getTokenVerifier)();
|
|
20
|
-
|
|
22
|
+
const isValid = await tokenVerifier.verify(accessToken);
|
|
23
|
+
if (!isValid) {
|
|
24
|
+
throw new ToolError_1.ToolError('Forbidden', 403, 'Invalid OptiID access token');
|
|
25
|
+
}
|
|
21
26
|
}
|
|
22
27
|
catch (error) {
|
|
28
|
+
if (error instanceof ToolError_1.ToolError) {
|
|
29
|
+
throw error;
|
|
30
|
+
}
|
|
23
31
|
app_sdk_1.logger.error('OptiID token validation failed:', error);
|
|
24
|
-
|
|
32
|
+
throw new ToolError_1.ToolError('Forbidden', 403, 'Token verification failed');
|
|
25
33
|
}
|
|
26
34
|
}
|
|
27
35
|
/**
|
|
28
36
|
* Extract and validate basic OptiID authentication data from request
|
|
29
37
|
*
|
|
30
38
|
* @param request - The incoming request
|
|
31
|
-
* @returns object with authData and accessToken, or null if
|
|
39
|
+
* @returns object with authData and accessToken, or null if auth is missing
|
|
32
40
|
*/
|
|
33
41
|
function extractAuthData(request) {
|
|
34
42
|
const authData = request?.bodyJSON?.auth;
|
|
43
|
+
if (!authData) {
|
|
44
|
+
return null;
|
|
45
|
+
}
|
|
46
|
+
if (authData?.provider?.toLowerCase() !== 'optiid') {
|
|
47
|
+
return null;
|
|
48
|
+
}
|
|
35
49
|
const accessToken = authData?.credentials?.access_token;
|
|
36
|
-
if (!accessToken
|
|
50
|
+
if (!accessToken) {
|
|
37
51
|
return null;
|
|
38
52
|
}
|
|
39
53
|
return { authData, accessToken };
|
|
40
54
|
}
|
|
55
|
+
/**
|
|
56
|
+
* Extract and validate auth data with error throwing for authentication flow
|
|
57
|
+
*
|
|
58
|
+
* @param request - The incoming request
|
|
59
|
+
* @returns object with authData and accessToken
|
|
60
|
+
* @throws {ToolError} If auth data is invalid or missing
|
|
61
|
+
*/
|
|
62
|
+
function extractAndValidateAuthData(request) {
|
|
63
|
+
const authData = request?.bodyJSON?.auth;
|
|
64
|
+
if (!authData) {
|
|
65
|
+
throw new ToolError_1.ToolError('Forbidden', 403, 'Authentication data is required');
|
|
66
|
+
}
|
|
67
|
+
if (authData?.provider?.toLowerCase() !== 'optiid') {
|
|
68
|
+
throw new ToolError_1.ToolError('Forbidden', 403, 'Only OptiID authentication provider is supported');
|
|
69
|
+
}
|
|
70
|
+
const accessToken = authData?.credentials?.access_token;
|
|
71
|
+
if (!accessToken) {
|
|
72
|
+
throw new ToolError_1.ToolError('Forbidden', 403, 'OptiID access token is required');
|
|
73
|
+
}
|
|
74
|
+
return { authData, accessToken };
|
|
75
|
+
}
|
|
41
76
|
/**
|
|
42
77
|
* Validate organization ID matches the app context
|
|
43
78
|
*
|
|
44
79
|
* @param customerId - The customer ID from the auth data
|
|
45
|
-
* @
|
|
80
|
+
* @throws {ToolError} If organization ID is invalid or missing
|
|
46
81
|
*/
|
|
47
82
|
function validateOrganizationId(customerId) {
|
|
48
83
|
if (!customerId) {
|
|
49
84
|
app_sdk_1.logger.error('Organisation ID is required but not provided');
|
|
50
|
-
|
|
85
|
+
throw new ToolError_1.ToolError('Forbidden', 403, 'Organization ID is required');
|
|
51
86
|
}
|
|
52
87
|
const appOrganisationId = (0, app_sdk_1.getAppContext)()?.account?.organizationId;
|
|
53
88
|
if (customerId !== appOrganisationId) {
|
|
54
89
|
app_sdk_1.logger.error(`Invalid organisation ID: expected ${appOrganisationId}, received ${customerId}`);
|
|
55
|
-
|
|
90
|
+
throw new ToolError_1.ToolError('Forbidden', 403, 'Organization ID does not match');
|
|
56
91
|
}
|
|
57
|
-
return true;
|
|
58
92
|
}
|
|
59
93
|
/**
|
|
60
94
|
* Check if a request should skip authentication (discovery/ready endpoints)
|
|
@@ -70,40 +104,61 @@ function shouldSkipAuth(request) {
|
|
|
70
104
|
*
|
|
71
105
|
* @param request - The incoming request
|
|
72
106
|
* @param validateOrg - Whether to validate organization ID
|
|
73
|
-
* @
|
|
107
|
+
* @throws {ToolError} If authentication fails
|
|
74
108
|
*/
|
|
75
109
|
async function authenticateRequest(request, validateOrg) {
|
|
76
110
|
if (shouldSkipAuth(request)) {
|
|
77
|
-
return
|
|
111
|
+
return;
|
|
78
112
|
}
|
|
79
|
-
const
|
|
80
|
-
if (!authInfo) {
|
|
81
|
-
app_sdk_1.logger.error('OptiID token is required but not provided');
|
|
82
|
-
return false;
|
|
83
|
-
}
|
|
84
|
-
const { authData, accessToken } = authInfo;
|
|
113
|
+
const { authData, accessToken } = extractAndValidateAuthData(request);
|
|
85
114
|
// Validate organization ID if required
|
|
86
|
-
if (validateOrg
|
|
87
|
-
|
|
115
|
+
if (validateOrg) {
|
|
116
|
+
validateOrganizationId(authData.credentials?.customer_id);
|
|
117
|
+
}
|
|
118
|
+
await validateAccessToken(accessToken);
|
|
119
|
+
}
|
|
120
|
+
/**
|
|
121
|
+
* Authenticate internal requests using OptiID token from headers
|
|
122
|
+
* @param request The request object
|
|
123
|
+
* @returns true if authentication succeeds
|
|
124
|
+
*/
|
|
125
|
+
async function authenticateInternalRequest(request) {
|
|
126
|
+
try {
|
|
127
|
+
const headers = request.headers;
|
|
128
|
+
const optiIdToken = headers?.get('Authorization') || headers?.get('authorization');
|
|
129
|
+
if (!optiIdToken) {
|
|
130
|
+
app_sdk_1.logger.info('OptiID token is required in Authorization header for internal requests');
|
|
131
|
+
throw new ToolError_1.ToolError('Unauthorized', 401, 'OptiID token is required');
|
|
132
|
+
}
|
|
133
|
+
// Validate the token using TokenVerifier directly
|
|
134
|
+
const tokenVerifier = await (0, TokenVerifier_1.getTokenVerifier)();
|
|
135
|
+
const isValidToken = await tokenVerifier.verify(optiIdToken);
|
|
136
|
+
if (!isValidToken) {
|
|
137
|
+
app_sdk_1.logger.info('Invalid OptiID token provided for internal request');
|
|
138
|
+
throw new ToolError_1.ToolError('Unauthorized', 401, 'Invalid OptiID token');
|
|
139
|
+
}
|
|
140
|
+
}
|
|
141
|
+
catch (error) {
|
|
142
|
+
app_sdk_1.logger.error('Internal request authentication failed:', error);
|
|
143
|
+
throw new ToolError_1.ToolError('Unauthorized', 401, 'Internal request authentication failed');
|
|
88
144
|
}
|
|
89
|
-
return await validateAccessToken(accessToken);
|
|
90
145
|
}
|
|
91
146
|
/**
|
|
92
147
|
* Authenticate a request for regular functions (with organization validation)
|
|
93
148
|
*
|
|
94
149
|
* @param request - The incoming request
|
|
95
|
-
* @
|
|
150
|
+
* @throws {ToolError} If authentication or authorization fails
|
|
96
151
|
*/
|
|
97
152
|
async function authenticateRegularRequest(request) {
|
|
98
|
-
|
|
153
|
+
await authenticateRequest(request, true);
|
|
99
154
|
}
|
|
100
155
|
/**
|
|
101
156
|
* Authenticate a request for global functions (without organization validation)
|
|
102
157
|
*
|
|
103
158
|
* @param request - The incoming request
|
|
104
|
-
* @
|
|
159
|
+
* @throws {ToolError} If authentication fails
|
|
105
160
|
*/
|
|
106
161
|
async function authenticateGlobalRequest(request) {
|
|
107
|
-
|
|
162
|
+
await authenticateRequest(request, false);
|
|
108
163
|
}
|
|
109
164
|
//# sourceMappingURL=AuthUtils.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"AuthUtils.js","sourceRoot":"","sources":["../../src/auth/AuthUtils.ts"],"names":[],"mappings":";;
|
|
1
|
+
{"version":3,"file":"AuthUtils.js","sourceRoot":"","sources":["../../src/auth/AuthUtils.ts"],"names":[],"mappings":";;AAoCA,0CAiBC;AAoFD,kEAsBC;AAQD,gEAEC;AAQD,8DAEC;AAnLD,+CAAmE;AACnE,mDAAmD;AAEnD,kDAA+C;AAE/C;;;;;GAKG;AACH,KAAK,UAAU,mBAAmB,CAAC,WAA+B;IAChE,IAAI,CAAC;QACH,IAAI,CAAC,WAAW,EAAE,CAAC;YACjB,MAAM,IAAI,qBAAS,CAAC,WAAW,EAAE,GAAG,EAAE,iCAAiC,CAAC,CAAC;QAC3E,CAAC;QACD,MAAM,aAAa,GAAG,MAAM,IAAA,gCAAgB,GAAE,CAAC;QAC/C,MAAM,OAAO,GAAG,MAAM,aAAa,CAAC,MAAM,CAAC,WAAW,CAAC,CAAC;QACxD,IAAI,CAAC,OAAO,EAAE,CAAC;YACb,MAAM,IAAI,qBAAS,CAAC,WAAW,EAAE,GAAG,EAAE,6BAA6B,CAAC,CAAC;QACvE,CAAC;IACH,CAAC;IAAC,OAAO,KAAK,EAAE,CAAC;QACf,IAAI,KAAK,YAAY,qBAAS,EAAE,CAAC;YAC/B,MAAM,KAAK,CAAC;QACd,CAAC;QACD,gBAAM,CAAC,KAAK,CAAC,iCAAiC,EAAE,KAAK,CAAC,CAAC;QACvD,MAAM,IAAI,qBAAS,CAAC,WAAW,EAAE,GAAG,EAAE,2BAA2B,CAAC,CAAC;IACrE,CAAC;AACH,CAAC;AAED;;;;;GAKG;AACH,SAAgB,eAAe,CAAC,OAAY;IAC1C,MAAM,QAAQ,GAAG,OAAO,EAAE,QAAQ,EAAE,IAAsB,CAAC;IAE3D,IAAI,CAAC,QAAQ,EAAE,CAAC;QACd,OAAO,IAAI,CAAC;IACd,CAAC;IAED,IAAI,QAAQ,EAAE,QAAQ,EAAE,WAAW,EAAE,KAAK,QAAQ,EAAE,CAAC;QACnD,OAAO,IAAI,CAAC;IACd,CAAC;IAED,MAAM,WAAW,GAAG,QAAQ,EAAE,WAAW,EAAE,YAAY,CAAC;IACxD,IAAI,CAAC,WAAW,EAAE,CAAC;QACjB,OAAO,IAAI,CAAC;IACd,CAAC;IAED,OAAO,EAAE,QAAQ,EAAE,WAAW,EAAE,CAAC;AACnC,CAAC;AAED;;;;;;GAMG;AACH,SAAS,0BAA0B,CAAC,OAAY;IAC9C,MAAM,QAAQ,GAAG,OAAO,EAAE,QAAQ,EAAE,IAAsB,CAAC;IAE3D,IAAI,CAAC,QAAQ,EAAE,CAAC;QACd,MAAM,IAAI,qBAAS,CAAC,WAAW,EAAE,GAAG,EAAE,iCAAiC,CAAC,CAAC;IAC3E,CAAC;IAED,IAAI,QAAQ,EAAE,QAAQ,EAAE,WAAW,EAAE,KAAK,QAAQ,EAAE,CAAC;QACnD,MAAM,IAAI,qBAAS,CAAC,WAAW,EAAE,GAAG,EAAE,kDAAkD,CAAC,CAAC;IAC5F,CAAC;IAED,MAAM,WAAW,GAAG,QAAQ,EAAE,WAAW,EAAE,YAAY,CAAC;IACxD,IAAI,CAAC,WAAW,EAAE,CAAC;QACjB,MAAM,IAAI,qBAAS,CAAC,WAAW,EAAE,GAAG,EAAE,iCAAiC,CAAC,CAAC;IAC3E,CAAC;IAED,OAAO,EAAE,QAAQ,EAAE,WAAW,EAAE,CAAC;AACnC,CAAC;AAED;;;;;GAKG;AACH,SAAS,sBAAsB,CAAC,UAA8B;IAC5D,IAAI,CAAC,UAAU,EAAE,CAAC;QAChB,gBAAM,CAAC,KAAK,CAAC,8CAA8C,CAAC,CAAC;QAC7D,MAAM,IAAI,qBAAS,CAAC,WAAW,EAAE,GAAG,EAAE,6BAA6B,CAAC,CAAC;IACvE,CAAC;IAED,MAAM,iBAAiB,GAAG,IAAA,uBAAa,GAAE,EAAE,OAAO,EAAE,cAAc,CAAC;IACnE,IAAI,UAAU,KAAK,iBAAiB,EAAE,CAAC;QACrC,gBAAM,CAAC,KAAK,CAAC,qCAAqC,iBAAiB,cAAc,UAAU,EAAE,CAAC,CAAC;QAC/F,MAAM,IAAI,qBAAS,CAAC,WAAW,EAAE,GAAG,EAAE,gCAAgC,CAAC,CAAC;IAC1E,CAAC;AACH,CAAC;AAED;;;;;GAKG;AACH,SAAS,cAAc,CAAC,OAAY;IAClC,OAAO,OAAO,CAAC,IAAI,KAAK,YAAY,IAAI,OAAO,CAAC,IAAI,KAAK,QAAQ,CAAC;AACpE,CAAC;AAED;;;;;;GAMG;AACH,KAAK,UAAU,mBAAmB,CAAC,OAAY,EAAE,WAAoB;IACnE,IAAI,cAAc,CAAC,OAAO,CAAC,EAAE,CAAC;QAC5B,OAAO;IACT,CAAC;IAED,MAAM,EAAE,QAAQ,EAAE,WAAW,EAAE,GAAG,0BAA0B,CAAC,OAAO,CAAC,CAAC;IAEtE,uCAAuC;IACvC,IAAI,WAAW,EAAE,CAAC;QAChB,sBAAsB,CAAC,QAAQ,CAAC,WAAW,EAAE,WAAW,CAAC,CAAC;IAC5D,CAAC;IAED,MAAM,mBAAmB,CAAC,WAAW,CAAC,CAAC;AACzC,CAAC;AAED;;;;GAIG;AACI,KAAK,UAAU,2BAA2B,CAAC,OAAgB;IAChE,IAAI,CAAC;QACH,MAAM,OAAO,GAAG,OAAO,CAAC,OAAO,CAAC;QAChC,MAAM,WAAW,GAAG,OAAO,EAAE,GAAG,CAAC,eAAe,CAAC,IAAI,OAAO,EAAE,GAAG,CAAC,eAAe,CAAC,CAAC;QAEnF,IAAI,CAAC,WAAW,EAAE,CAAC;YACjB,gBAAM,CAAC,IAAI,CAAC,wEAAwE,CAAC,CAAC;YACtF,MAAM,IAAI,qBAAS,CAAC,cAAc,EAAE,GAAG,EAAE,0BAA0B,CAAC,CAAC;QACvE,CAAC;QAED,kDAAkD;QAClD,MAAM,aAAa,GAAG,MAAM,IAAA,gCAAgB,GAAE,CAAC;QAC/C,MAAM,YAAY,GAAG,MAAM,aAAa,CAAC,MAAM,CAAC,WAAW,CAAC,CAAC;QAE7D,IAAI,CAAC,YAAY,EAAE,CAAC;YAClB,gBAAM,CAAC,IAAI,CAAC,oDAAoD,CAAC,CAAC;YAClE,MAAM,IAAI,qBAAS,CAAC,cAAc,EAAE,GAAG,EAAE,sBAAsB,CAAC,CAAC;QACnE,CAAC;IACH,CAAC;IAAC,OAAO,KAAU,EAAE,CAAC;QACpB,gBAAM,CAAC,KAAK,CAAC,yCAAyC,EAAE,KAAK,CAAC,CAAC;QAC/D,MAAM,IAAI,qBAAS,CAAC,cAAc,EAAE,GAAG,EAAE,wCAAwC,CAAC,CAAC;IACrF,CAAC;AACH,CAAC;AAED;;;;;GAKG;AACI,KAAK,UAAU,0BAA0B,CAAC,OAAY;IAC3D,MAAM,mBAAmB,CAAC,OAAO,EAAE,IAAI,CAAC,CAAC;AAC3C,CAAC;AAED;;;;;GAKG;AACI,KAAK,UAAU,yBAAyB,CAAC,OAAY;IAC1D,MAAM,mBAAmB,CAAC,OAAO,EAAE,KAAK,CAAC,CAAC;AAC5C,CAAC"}
|