@auth0/ai 1.0.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/LICENSE +176 -0
- package/README.md +44 -0
- package/dist/cjs/TokenResponse.js +3 -0
- package/dist/cjs/TokenResponse.js.map +1 -0
- package/dist/cjs/authorizers/ciba/CIBAAuthorizationRequest.js +3 -0
- package/dist/cjs/authorizers/ciba/CIBAAuthorizationRequest.js.map +1 -0
- package/dist/cjs/authorizers/ciba/CIBAAuthorizerBase.js +201 -0
- package/dist/cjs/authorizers/ciba/CIBAAuthorizerBase.js.map +1 -0
- package/dist/cjs/authorizers/ciba/CIBAAuthorizerParams.js +3 -0
- package/dist/cjs/authorizers/ciba/CIBAAuthorizerParams.js.map +1 -0
- package/dist/cjs/authorizers/ciba/asyncLocalStorage.js +14 -0
- package/dist/cjs/authorizers/ciba/asyncLocalStorage.js.map +1 -0
- package/dist/cjs/authorizers/ciba/index.js +9 -0
- package/dist/cjs/authorizers/ciba/index.js.map +1 -0
- package/dist/cjs/authorizers/device-authorizer.js +130 -0
- package/dist/cjs/authorizers/device-authorizer.js.map +1 -0
- package/dist/cjs/authorizers/federated-connections/asyncLocalStorage.js +14 -0
- package/dist/cjs/authorizers/federated-connections/asyncLocalStorage.js.map +1 -0
- package/dist/cjs/authorizers/federated-connections/index.js +129 -0
- package/dist/cjs/authorizers/federated-connections/index.js.map +1 -0
- package/dist/cjs/authorizers/fga/fga-client.js +30 -0
- package/dist/cjs/authorizers/fga/fga-client.js.map +1 -0
- package/dist/cjs/authorizers/fga/fga-filter.js +94 -0
- package/dist/cjs/authorizers/fga/fga-filter.js.map +1 -0
- package/dist/cjs/authorizers/fga/index.js +37 -0
- package/dist/cjs/authorizers/fga/index.js.map +1 -0
- package/dist/cjs/authorizers/index.js +3 -0
- package/dist/cjs/authorizers/index.js.map +1 -0
- package/dist/cjs/credentials.js +3 -0
- package/dist/cjs/credentials.js.map +1 -0
- package/dist/cjs/errors.js +46 -0
- package/dist/cjs/errors.js.map +1 -0
- package/dist/cjs/index.js +22 -0
- package/dist/cjs/index.js.map +1 -0
- package/dist/cjs/interrupts/Auth0Interrupt.js +46 -0
- package/dist/cjs/interrupts/Auth0Interrupt.js.map +1 -0
- package/dist/cjs/interrupts/CIBAInterrupts.js +89 -0
- package/dist/cjs/interrupts/CIBAInterrupts.js.map +1 -0
- package/dist/cjs/interrupts/FederatedConnectionInterrupt.js +31 -0
- package/dist/cjs/interrupts/FederatedConnectionInterrupt.js.map +1 -0
- package/dist/cjs/interrupts/index.js +17 -0
- package/dist/cjs/interrupts/index.js.map +1 -0
- package/dist/cjs/parameters.js +13 -0
- package/dist/cjs/parameters.js.map +1 -0
- package/dist/esm/TokenResponse.d.ts +15 -0
- package/dist/esm/TokenResponse.js +2 -0
- package/dist/esm/TokenResponse.js.map +1 -0
- package/dist/esm/authorizers/ciba/CIBAAuthorizationRequest.d.ts +20 -0
- package/dist/esm/authorizers/ciba/CIBAAuthorizationRequest.js +2 -0
- package/dist/esm/authorizers/ciba/CIBAAuthorizationRequest.js.map +1 -0
- package/dist/esm/authorizers/ciba/CIBAAuthorizerBase.d.ts +31 -0
- package/dist/esm/authorizers/ciba/CIBAAuthorizerBase.js +197 -0
- package/dist/esm/authorizers/ciba/CIBAAuthorizerBase.js.map +1 -0
- package/dist/esm/authorizers/ciba/CIBAAuthorizerParams.d.ts +66 -0
- package/dist/esm/authorizers/ciba/CIBAAuthorizerParams.js +2 -0
- package/dist/esm/authorizers/ciba/CIBAAuthorizerParams.js.map +1 -0
- package/dist/esm/authorizers/ciba/asyncLocalStorage.d.ts +16 -0
- package/dist/esm/authorizers/ciba/asyncLocalStorage.js +10 -0
- package/dist/esm/authorizers/ciba/asyncLocalStorage.js.map +1 -0
- package/dist/esm/authorizers/ciba/index.d.ts +4 -0
- package/dist/esm/authorizers/ciba/index.js +3 -0
- package/dist/esm/authorizers/ciba/index.js.map +1 -0
- package/dist/esm/authorizers/device-authorizer.d.ts +15 -0
- package/dist/esm/authorizers/device-authorizer.js +90 -0
- package/dist/esm/authorizers/device-authorizer.js.map +1 -0
- package/dist/esm/authorizers/federated-connections/asyncLocalStorage.d.ts +26 -0
- package/dist/esm/authorizers/federated-connections/asyncLocalStorage.js +10 -0
- package/dist/esm/authorizers/federated-connections/asyncLocalStorage.js.map +1 -0
- package/dist/esm/authorizers/federated-connections/index.d.ts +38 -0
- package/dist/esm/authorizers/federated-connections/index.js +123 -0
- package/dist/esm/authorizers/federated-connections/index.js.map +1 -0
- package/dist/esm/authorizers/fga/fga-client.d.ts +16 -0
- package/dist/esm/authorizers/fga/fga-client.js +27 -0
- package/dist/esm/authorizers/fga/fga-client.js.map +1 -0
- package/dist/esm/authorizers/fga/fga-filter.d.ts +63 -0
- package/dist/esm/authorizers/fga/fga-filter.js +90 -0
- package/dist/esm/authorizers/fga/fga-filter.js.map +1 -0
- package/dist/esm/authorizers/fga/index.d.ts +21 -0
- package/dist/esm/authorizers/fga/index.js +33 -0
- package/dist/esm/authorizers/fga/index.js.map +1 -0
- package/dist/esm/authorizers/index.d.ts +13 -0
- package/dist/esm/authorizers/index.js +2 -0
- package/dist/esm/authorizers/index.js.map +1 -0
- package/dist/esm/credentials.d.ts +10 -0
- package/dist/esm/credentials.js +2 -0
- package/dist/esm/credentials.js.map +1 -0
- package/dist/esm/errors.d.ts +19 -0
- package/dist/esm/errors.js +37 -0
- package/dist/esm/errors.js.map +1 -0
- package/dist/esm/index.d.ts +9 -0
- package/dist/esm/index.js +6 -0
- package/dist/esm/index.js.map +1 -0
- package/dist/esm/interrupts/Auth0Interrupt.d.ts +37 -0
- package/dist/esm/interrupts/Auth0Interrupt.js +42 -0
- package/dist/esm/interrupts/Auth0Interrupt.js.map +1 -0
- package/dist/esm/interrupts/CIBAInterrupts.d.ts +62 -0
- package/dist/esm/interrupts/CIBAInterrupts.js +79 -0
- package/dist/esm/interrupts/CIBAInterrupts.js.map +1 -0
- package/dist/esm/interrupts/FederatedConnectionInterrupt.d.ts +33 -0
- package/dist/esm/interrupts/FederatedConnectionInterrupt.js +26 -0
- package/dist/esm/interrupts/FederatedConnectionInterrupt.js.map +1 -0
- package/dist/esm/interrupts/index.d.ts +4 -0
- package/dist/esm/interrupts/index.js +4 -0
- package/dist/esm/interrupts/index.js.map +1 -0
- package/dist/esm/parameters.d.ts +3 -0
- package/dist/esm/parameters.js +9 -0
- package/dist/esm/parameters.js.map +1 -0
- package/package.json +76 -0
|
@@ -0,0 +1,130 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
|
|
3
|
+
if (k2 === undefined) k2 = k;
|
|
4
|
+
var desc = Object.getOwnPropertyDescriptor(m, k);
|
|
5
|
+
if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
|
|
6
|
+
desc = { enumerable: true, get: function() { return m[k]; } };
|
|
7
|
+
}
|
|
8
|
+
Object.defineProperty(o, k2, desc);
|
|
9
|
+
}) : (function(o, m, k, k2) {
|
|
10
|
+
if (k2 === undefined) k2 = k;
|
|
11
|
+
o[k2] = m[k];
|
|
12
|
+
}));
|
|
13
|
+
var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
|
|
14
|
+
Object.defineProperty(o, "default", { enumerable: true, value: v });
|
|
15
|
+
}) : function(o, v) {
|
|
16
|
+
o["default"] = v;
|
|
17
|
+
});
|
|
18
|
+
var __importStar = (this && this.__importStar) || (function () {
|
|
19
|
+
var ownKeys = function(o) {
|
|
20
|
+
ownKeys = Object.getOwnPropertyNames || function (o) {
|
|
21
|
+
var ar = [];
|
|
22
|
+
for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
|
|
23
|
+
return ar;
|
|
24
|
+
};
|
|
25
|
+
return ownKeys(o);
|
|
26
|
+
};
|
|
27
|
+
return function (mod) {
|
|
28
|
+
if (mod && mod.__esModule) return mod;
|
|
29
|
+
var result = {};
|
|
30
|
+
if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
|
|
31
|
+
__setModuleDefault(result, mod);
|
|
32
|
+
return result;
|
|
33
|
+
};
|
|
34
|
+
})();
|
|
35
|
+
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
36
|
+
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
37
|
+
};
|
|
38
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
39
|
+
exports.DeviceAuthorizer = void 0;
|
|
40
|
+
const enquirer_1 = __importDefault(require("enquirer"));
|
|
41
|
+
const jose = __importStar(require("jose"));
|
|
42
|
+
const open_1 = __importDefault(require("open"));
|
|
43
|
+
const openid_client_1 = require("openid-client");
|
|
44
|
+
const errors_1 = require("../errors");
|
|
45
|
+
class DeviceAuthorizer {
|
|
46
|
+
constructor(params) {
|
|
47
|
+
this.domain = (params === null || params === void 0 ? void 0 : params.domain) || process.env.AUTH0_DOMAIN;
|
|
48
|
+
this.clientId = (params === null || params === void 0 ? void 0 : params.clientId) || process.env.AUTH0_CLIENT_ID;
|
|
49
|
+
}
|
|
50
|
+
async _authorize(params) {
|
|
51
|
+
const config = await (0, openid_client_1.discovery)(new URL(`https://${this.domain}`), this.clientId);
|
|
52
|
+
const handle = await (0, openid_client_1.initiateDeviceAuthorization)(config, {
|
|
53
|
+
...params,
|
|
54
|
+
});
|
|
55
|
+
const { verification_uri_complete, user_code, expires_in } = handle;
|
|
56
|
+
const enquirer = new enquirer_1.default();
|
|
57
|
+
await enquirer.prompt({
|
|
58
|
+
type: "input",
|
|
59
|
+
name: "confirmation",
|
|
60
|
+
message: `Press Enter to open the browser to log in or press Ctrl+C to abort. You should see the following code: ${user_code}. It expires in ${expires_in % 60 === 0
|
|
61
|
+
? `${expires_in / 60} minutes`
|
|
62
|
+
: `${expires_in} seconds`}.`,
|
|
63
|
+
});
|
|
64
|
+
await (0, open_1.default)(verification_uri_complete);
|
|
65
|
+
let tokens = null;
|
|
66
|
+
try {
|
|
67
|
+
tokens = await (0, openid_client_1.pollDeviceAuthorizationGrant)(config, handle);
|
|
68
|
+
}
|
|
69
|
+
catch (err) {
|
|
70
|
+
switch (err.error) {
|
|
71
|
+
case "access_denied":
|
|
72
|
+
throw new errors_1.AccessDeniedError(err.error_description);
|
|
73
|
+
case "expired_token":
|
|
74
|
+
throw new errors_1.AuthorizationRequestExpiredError("Authorization request has expired");
|
|
75
|
+
default:
|
|
76
|
+
throw new Error(`Error: ${err.error}; Description: ${err.error_description}`);
|
|
77
|
+
}
|
|
78
|
+
}
|
|
79
|
+
if (!tokens) {
|
|
80
|
+
throw new Error("Failed to obtain tokens");
|
|
81
|
+
}
|
|
82
|
+
const credentials = {
|
|
83
|
+
accessToken: {
|
|
84
|
+
type: tokens.token_type || "bearer",
|
|
85
|
+
value: tokens.access_token,
|
|
86
|
+
},
|
|
87
|
+
};
|
|
88
|
+
if (tokens.id_token) {
|
|
89
|
+
credentials.idToken = {
|
|
90
|
+
type: tokens.token_type || "bearer",
|
|
91
|
+
value: tokens.id_token,
|
|
92
|
+
};
|
|
93
|
+
}
|
|
94
|
+
return credentials;
|
|
95
|
+
}
|
|
96
|
+
static async authorize(options, params) {
|
|
97
|
+
const authorizer = new DeviceAuthorizer(params);
|
|
98
|
+
const credentials = await authorizer._authorize(options);
|
|
99
|
+
let claims = {};
|
|
100
|
+
if (credentials.idToken) {
|
|
101
|
+
claims = jose.decodeJwt(credentials.idToken.value);
|
|
102
|
+
}
|
|
103
|
+
return { accessToken: credentials.accessToken.value, claims };
|
|
104
|
+
}
|
|
105
|
+
static create(params) {
|
|
106
|
+
const authorizer = new DeviceAuthorizer(params);
|
|
107
|
+
return (options) => {
|
|
108
|
+
return function deviceFlow(handler, onError) {
|
|
109
|
+
return async (input, config) => {
|
|
110
|
+
try {
|
|
111
|
+
const credentials = await authorizer._authorize(options);
|
|
112
|
+
let claims = {};
|
|
113
|
+
if (credentials.idToken) {
|
|
114
|
+
claims = jose.decodeJwt(credentials.idToken.value);
|
|
115
|
+
}
|
|
116
|
+
return handler({ accessToken: credentials.accessToken.value, claims }, input, config);
|
|
117
|
+
}
|
|
118
|
+
catch (e) {
|
|
119
|
+
if (typeof onError === "function") {
|
|
120
|
+
return onError(e);
|
|
121
|
+
}
|
|
122
|
+
return "Access denied.";
|
|
123
|
+
}
|
|
124
|
+
};
|
|
125
|
+
};
|
|
126
|
+
};
|
|
127
|
+
}
|
|
128
|
+
}
|
|
129
|
+
exports.DeviceAuthorizer = DeviceAuthorizer;
|
|
130
|
+
//# sourceMappingURL=device-authorizer.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"device-authorizer.js","sourceRoot":"","sources":["../../../src/authorizers/device-authorizer.ts"],"names":[],"mappings":"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","sourcesContent":["import Enquirer from \"enquirer\";\nimport * as jose from \"jose\";\nimport open from \"open\";\nimport {\n discovery,\n initiateDeviceAuthorization,\n pollDeviceAuthorizationGrant,\n TokenEndpointResponse,\n TokenEndpointResponseHelpers,\n} from \"openid-client\";\n\nimport { Credentials } from \"../credentials\";\nimport { AccessDeniedError, AuthorizationRequestExpiredError } from \"../errors\";\nimport { AuthorizerParams, AuthParams, ToolWithAuthHandler } from \"./\";\n\nexport type DeviceAuthorizerOptions = {\n scope: string;\n audience?: string;\n};\n\nexport class DeviceAuthorizer {\n domain: string;\n clientId: string;\n\n private constructor(params?: AuthorizerParams) {\n this.domain = params?.domain || process.env.AUTH0_DOMAIN!;\n this.clientId = params?.clientId || process.env.AUTH0_CLIENT_ID!;\n }\n\n private async _authorize(\n params: DeviceAuthorizerOptions\n ): Promise<Credentials> {\n const config = await discovery(\n new URL(`https://${this.domain}`),\n this.clientId\n );\n\n const handle = await initiateDeviceAuthorization(config, {\n ...params,\n });\n\n const { verification_uri_complete, user_code, expires_in } = handle;\n\n const enquirer = new Enquirer();\n await enquirer.prompt({\n type: \"input\",\n name: \"confirmation\",\n message: `Press Enter to open the browser to log in or press Ctrl+C to abort. You should see the following code: ${user_code}. It expires in ${\n expires_in % 60 === 0\n ? `${expires_in / 60} minutes`\n : `${expires_in} seconds`\n }.`,\n });\n\n await open(verification_uri_complete!);\n\n let tokens: (TokenEndpointResponse & TokenEndpointResponseHelpers) | null =\n null;\n\n try {\n tokens = await pollDeviceAuthorizationGrant(config, handle);\n } catch (err: any) {\n switch (err.error) {\n case \"access_denied\":\n throw new AccessDeniedError(err.error_description);\n case \"expired_token\":\n throw new AuthorizationRequestExpiredError(\n \"Authorization request has expired\"\n );\n default:\n throw new Error(\n `Error: ${err.error}; Description: ${err.error_description}`\n );\n }\n }\n\n if (!tokens) {\n throw new Error(\"Failed to obtain tokens\");\n }\n\n const credentials: Credentials = {\n accessToken: {\n type: tokens.token_type || \"bearer\",\n value: tokens.access_token,\n },\n };\n\n if (tokens.id_token) {\n credentials.idToken = {\n type: tokens.token_type || \"bearer\",\n value: tokens.id_token,\n };\n }\n\n return credentials;\n }\n\n static async authorize(\n options: DeviceAuthorizerOptions,\n params?: AuthorizerParams\n ) {\n const authorizer = new DeviceAuthorizer(params);\n const credentials = await authorizer._authorize(options);\n\n let claims = {};\n\n if (credentials.idToken) {\n claims = jose.decodeJwt(credentials.idToken!.value);\n }\n\n return { accessToken: credentials.accessToken.value, claims } as AuthParams;\n }\n\n static create(params?: AuthorizerParams): DeviceFlowInstance {\n const authorizer = new DeviceAuthorizer(params);\n\n return (options: DeviceAuthorizerOptions) => {\n return function deviceFlow<I, O, C>(\n handler: ToolWithAuthHandler<I, O, C>,\n onError?: (error: Error) => Promise<O>\n ) {\n return async (input: I, config?: C): Promise<O> => {\n try {\n const credentials = await authorizer._authorize(options);\n let claims = {};\n\n if (credentials.idToken) {\n claims = jose.decodeJwt(credentials.idToken!.value);\n }\n\n return handler(\n { accessToken: credentials.accessToken.value, claims },\n input,\n config\n );\n } catch (e: any) {\n if (typeof onError === \"function\") {\n return onError(e);\n }\n\n return \"Access denied.\" as O;\n }\n };\n };\n };\n }\n}\n\nexport type DeviceFlowInstance = (\n options: DeviceAuthorizerOptions\n) => <I, O, C>(\n handler: ToolWithAuthHandler<I, O, C>,\n onError?: (error: Error) => Promise<O>\n) => (input: I, config?: C) => Promise<O>;\n"]}
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.getAccessTokenForConnection = exports.asyncLocalStorage = void 0;
|
|
4
|
+
const node_async_hooks_1 = require("node:async_hooks");
|
|
5
|
+
exports.asyncLocalStorage = new node_async_hooks_1.AsyncLocalStorage();
|
|
6
|
+
const getAccessTokenForConnection = () => {
|
|
7
|
+
const store = exports.asyncLocalStorage.getStore();
|
|
8
|
+
if (typeof store === "undefined") {
|
|
9
|
+
throw new Error("The tool must be wrapped with the withFederatedConnections function.");
|
|
10
|
+
}
|
|
11
|
+
return store === null || store === void 0 ? void 0 : store.accessToken;
|
|
12
|
+
};
|
|
13
|
+
exports.getAccessTokenForConnection = getAccessTokenForConnection;
|
|
14
|
+
//# sourceMappingURL=asyncLocalStorage.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"asyncLocalStorage.js","sourceRoot":"","sources":["../../../../src/authorizers/federated-connections/asyncLocalStorage.ts"],"names":[],"mappings":";;;AAAA,uDAAqD;AA6BxC,QAAA,iBAAiB,GAAG,IAAI,oCAAiB,EAEnD,CAAC;AAEG,MAAM,2BAA2B,GAAG,GAAG,EAAE;IAC9C,MAAM,KAAK,GAAG,yBAAiB,CAAC,QAAQ,EAAE,CAAC;IAC3C,IAAI,OAAO,KAAK,KAAK,WAAW,EAAE,CAAC;QACjC,MAAM,IAAI,KAAK,CACb,sEAAsE,CACvE,CAAC;IACJ,CAAC;IACD,OAAO,KAAK,aAAL,KAAK,uBAAL,KAAK,CAAE,WAAW,CAAC;AAC5B,CAAC,CAAC;AARW,QAAA,2BAA2B,+BAQtC","sourcesContent":["import { AsyncLocalStorage } from \"node:async_hooks\";\n\nexport type AsyncStorageValue<TContext> = {\n /**\n * The Federated Connection access token.\n */\n accessToken?: string;\n\n /**\n * The tool execution context.\n */\n context: TContext;\n\n /**\n * The federated connection name.\n */\n connection: string;\n\n /**\n * The scopes required to access the federated connection.\n */\n scopes: string[];\n\n /**\n * The scopes that the current access token has.\n */\n currentScopes?: string[];\n};\n\nexport const asyncLocalStorage = new AsyncLocalStorage<\n AsyncStorageValue<any>\n>();\n\nexport const getAccessTokenForConnection = () => {\n const store = asyncLocalStorage.getStore();\n if (typeof store === \"undefined\") {\n throw new Error(\n \"The tool must be wrapped with the withFederatedConnections function.\"\n );\n }\n return store?.accessToken;\n};\n"]}
|
|
@@ -0,0 +1,129 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.FederatedConnectionAuthorizerBase = exports.getAccessTokenForConnection = exports.asyncLocalStorage = void 0;
|
|
4
|
+
const interrupts_1 = require("../../interrupts");
|
|
5
|
+
const parameters_1 = require("../../parameters");
|
|
6
|
+
const asyncLocalStorage_1 = require("./asyncLocalStorage");
|
|
7
|
+
var asyncLocalStorage_2 = require("./asyncLocalStorage");
|
|
8
|
+
Object.defineProperty(exports, "asyncLocalStorage", { enumerable: true, get: function () { return asyncLocalStorage_2.asyncLocalStorage; } });
|
|
9
|
+
Object.defineProperty(exports, "getAccessTokenForConnection", { enumerable: true, get: function () { return asyncLocalStorage_2.getAccessTokenForConnection; } });
|
|
10
|
+
/**
|
|
11
|
+
* Requests authorization to a third party service via Federated Connection.
|
|
12
|
+
*/
|
|
13
|
+
class FederatedConnectionAuthorizerBase {
|
|
14
|
+
constructor(auth0, params) {
|
|
15
|
+
this.auth0 = auth0;
|
|
16
|
+
this.params = params;
|
|
17
|
+
if (typeof params.refreshToken === "undefined" &&
|
|
18
|
+
typeof params.accessToken === "undefined") {
|
|
19
|
+
throw new Error("Either refreshToken or accessToken must be provided to initialize the Authorizer.");
|
|
20
|
+
}
|
|
21
|
+
if (typeof params.accessToken !== "undefined" &&
|
|
22
|
+
typeof params.refreshToken !== "undefined") {
|
|
23
|
+
throw new Error("Only one of refreshToken or accessToken can be provided to initialize the Authorizer.");
|
|
24
|
+
}
|
|
25
|
+
}
|
|
26
|
+
handleAuthorizationInterrupts(err) {
|
|
27
|
+
throw err;
|
|
28
|
+
}
|
|
29
|
+
validateToken(tokenResponse) {
|
|
30
|
+
var _a;
|
|
31
|
+
const store = asyncLocalStorage_1.asyncLocalStorage.getStore();
|
|
32
|
+
if (!store) {
|
|
33
|
+
throw new Error("The tool must be wrapped with the FederationConnectionAuthorizer.");
|
|
34
|
+
}
|
|
35
|
+
const { scopes, connection } = store;
|
|
36
|
+
if (!tokenResponse) {
|
|
37
|
+
throw new interrupts_1.FederatedConnectionInterrupt(`Authorization required to access the Federated Connection: ${this.params.connection}`, connection, scopes, scopes);
|
|
38
|
+
}
|
|
39
|
+
const currentScopes = ((_a = tokenResponse.scope) !== null && _a !== void 0 ? _a : "").split(" ");
|
|
40
|
+
const missingScopes = scopes.filter((s) => !currentScopes.includes(s));
|
|
41
|
+
store.currentScopes = currentScopes;
|
|
42
|
+
if (missingScopes.length > 0) {
|
|
43
|
+
throw new interrupts_1.FederatedConnectionInterrupt(`Authorization required to access the Federated Connection: ${this.params.connection}. Missing scopes: ${missingScopes.join(", ")}`, connection, scopes, [...currentScopes, ...scopes]);
|
|
44
|
+
}
|
|
45
|
+
}
|
|
46
|
+
async getAccessTokenImpl(...toolContext) {
|
|
47
|
+
const store = asyncLocalStorage_1.asyncLocalStorage.getStore();
|
|
48
|
+
if (!store) {
|
|
49
|
+
throw new Error("The tool must be wrapped with the FederationConnectionAuthorizer.");
|
|
50
|
+
}
|
|
51
|
+
const { connection } = store;
|
|
52
|
+
const subjectToken = await this.getRefreshToken(...toolContext);
|
|
53
|
+
if (!subjectToken) {
|
|
54
|
+
return;
|
|
55
|
+
}
|
|
56
|
+
const exchangeParams = {
|
|
57
|
+
grant_type: "urn:auth0:params:oauth:grant-type:token-exchange:federated-connection-access-token",
|
|
58
|
+
client_id: this.auth0.clientId,
|
|
59
|
+
client_secret: this.auth0.clientSecret,
|
|
60
|
+
subject_token_type: "urn:ietf:params:oauth:token-type:refresh_token",
|
|
61
|
+
subject_token: subjectToken,
|
|
62
|
+
connection: connection,
|
|
63
|
+
requested_token_type: "http://auth0.com/oauth/token-type/federated-connection-access-token",
|
|
64
|
+
};
|
|
65
|
+
const res = await fetch(`https://${this.auth0.domain}/oauth/token`, {
|
|
66
|
+
method: "POST",
|
|
67
|
+
headers: { "Content-Type": "application/json" },
|
|
68
|
+
body: JSON.stringify(exchangeParams),
|
|
69
|
+
});
|
|
70
|
+
if (!res.ok) {
|
|
71
|
+
return;
|
|
72
|
+
}
|
|
73
|
+
const tokenResponse = await res.json();
|
|
74
|
+
return tokenResponse;
|
|
75
|
+
}
|
|
76
|
+
async getAccessToken(...toolContext) {
|
|
77
|
+
let tokenResponse;
|
|
78
|
+
if (typeof this.params.refreshToken === "function") {
|
|
79
|
+
tokenResponse = await this.getAccessTokenImpl(...toolContext);
|
|
80
|
+
}
|
|
81
|
+
else {
|
|
82
|
+
tokenResponse = await (0, parameters_1.resolveParameter)(this.params.accessToken, toolContext);
|
|
83
|
+
}
|
|
84
|
+
this.validateToken(tokenResponse);
|
|
85
|
+
return tokenResponse;
|
|
86
|
+
}
|
|
87
|
+
async getRefreshToken(...toolContext) {
|
|
88
|
+
return await (0, parameters_1.resolveParameter)(this.params.refreshToken, toolContext);
|
|
89
|
+
}
|
|
90
|
+
/**
|
|
91
|
+
*
|
|
92
|
+
* Wraps the execute method of an AI tool to handle Federated Connections authorization.
|
|
93
|
+
*
|
|
94
|
+
* @param getContext - A function that returns the context of the tool execution.
|
|
95
|
+
* @param execute - The tool execute method.
|
|
96
|
+
* @returns The wrapped execute method.
|
|
97
|
+
*/
|
|
98
|
+
protect(getContext, execute) {
|
|
99
|
+
return async (...args) => {
|
|
100
|
+
const asyncStore = {
|
|
101
|
+
context: await getContext(...args),
|
|
102
|
+
scopes: await (0, parameters_1.resolveParameter)(this.params.scopes, args),
|
|
103
|
+
connection: await (0, parameters_1.resolveParameter)(this.params.connection, args),
|
|
104
|
+
};
|
|
105
|
+
if (asyncLocalStorage_1.asyncLocalStorage.getStore()) {
|
|
106
|
+
throw new Error("Cannot nest tool calls that require federated connection authorization.");
|
|
107
|
+
}
|
|
108
|
+
return asyncLocalStorage_1.asyncLocalStorage.run(asyncStore, async () => {
|
|
109
|
+
try {
|
|
110
|
+
const tokenResponse = await this.getAccessToken(...args);
|
|
111
|
+
asyncStore.accessToken = tokenResponse.access_token;
|
|
112
|
+
return await execute(...args);
|
|
113
|
+
}
|
|
114
|
+
catch (err) {
|
|
115
|
+
if (err instanceof interrupts_1.FederatedConnectionError) {
|
|
116
|
+
const interrupt = new interrupts_1.FederatedConnectionInterrupt(err.message, asyncStore.connection, asyncStore.scopes, asyncStore.scopes);
|
|
117
|
+
return this.handleAuthorizationInterrupts(interrupt);
|
|
118
|
+
}
|
|
119
|
+
if (err instanceof interrupts_1.Auth0Interrupt) {
|
|
120
|
+
return this.handleAuthorizationInterrupts(err);
|
|
121
|
+
}
|
|
122
|
+
throw err;
|
|
123
|
+
}
|
|
124
|
+
});
|
|
125
|
+
};
|
|
126
|
+
}
|
|
127
|
+
}
|
|
128
|
+
exports.FederatedConnectionAuthorizerBase = FederatedConnectionAuthorizerBase;
|
|
129
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../../../src/authorizers/federated-connections/index.ts"],"names":[],"mappings":"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","sourcesContent":["import {\n Auth0Interrupt,\n FederatedConnectionError,\n FederatedConnectionInterrupt,\n} from \"../../interrupts\";\nimport { AuthorizerToolParameter, resolveParameter } from \"../../parameters\";\nimport { TokenResponse } from \"../../TokenResponse\";\nimport { asyncLocalStorage, AsyncStorageValue } from \"./asyncLocalStorage\";\n\nexport type { AsyncStorageValue } from \"./asyncLocalStorage\";\n\nexport {\n asyncLocalStorage,\n getAccessTokenForConnection,\n} from \"./asyncLocalStorage\";\n\nexport type FederatedConnectionAuthorizerParams<ToolExecuteArgs extends any[]> =\n {\n refreshToken?: AuthorizerToolParameter<ToolExecuteArgs, string | undefined>;\n accessToken?: AuthorizerToolParameter<\n ToolExecuteArgs,\n TokenResponse | undefined\n >;\n scopes: AuthorizerToolParameter<ToolExecuteArgs, string[]>;\n connection: AuthorizerToolParameter<ToolExecuteArgs, string>;\n };\n\n/**\n * Requests authorization to a third party service via Federated Connection.\n */\nexport class FederatedConnectionAuthorizerBase<ToolExecuteArgs extends any[]> {\n constructor(\n private readonly auth0: {\n domain: string;\n clientId: string;\n clientSecret: string | undefined;\n },\n private params: FederatedConnectionAuthorizerParams<ToolExecuteArgs>\n ) {\n if (\n typeof params.refreshToken === \"undefined\" &&\n typeof params.accessToken === \"undefined\"\n ) {\n throw new Error(\n \"Either refreshToken or accessToken must be provided to initialize the Authorizer.\"\n );\n }\n\n if (\n typeof params.accessToken !== \"undefined\" &&\n typeof params.refreshToken !== \"undefined\"\n ) {\n throw new Error(\n \"Only one of refreshToken or accessToken can be provided to initialize the Authorizer.\"\n );\n }\n }\n\n protected handleAuthorizationInterrupts(err: Auth0Interrupt) {\n throw err;\n }\n\n protected validateToken(tokenResponse?: TokenResponse) {\n const store = asyncLocalStorage.getStore();\n if (!store) {\n throw new Error(\n \"The tool must be wrapped with the FederationConnectionAuthorizer.\"\n );\n }\n\n const { scopes, connection } = store;\n\n if (!tokenResponse) {\n throw new FederatedConnectionInterrupt(\n `Authorization required to access the Federated Connection: ${this.params.connection}`,\n connection,\n scopes,\n scopes\n );\n }\n\n const currentScopes = (tokenResponse.scope ?? \"\").split(\" \");\n const missingScopes = scopes.filter((s) => !currentScopes.includes(s));\n store.currentScopes = currentScopes;\n\n if (missingScopes.length > 0) {\n throw new FederatedConnectionInterrupt(\n `Authorization required to access the Federated Connection: ${\n this.params.connection\n }. Missing scopes: ${missingScopes.join(\", \")}`,\n connection,\n scopes,\n [...currentScopes, ...scopes]\n );\n }\n }\n\n private async getAccessTokenImpl(\n ...toolContext: ToolExecuteArgs\n ): Promise<TokenResponse | undefined> {\n const store = asyncLocalStorage.getStore();\n if (!store) {\n throw new Error(\n \"The tool must be wrapped with the FederationConnectionAuthorizer.\"\n );\n }\n\n const { connection } = store;\n\n const subjectToken = await this.getRefreshToken(...toolContext);\n\n if (!subjectToken) {\n return;\n }\n\n const exchangeParams = {\n grant_type:\n \"urn:auth0:params:oauth:grant-type:token-exchange:federated-connection-access-token\",\n client_id: this.auth0.clientId,\n client_secret: this.auth0.clientSecret,\n subject_token_type: \"urn:ietf:params:oauth:token-type:refresh_token\",\n subject_token: subjectToken,\n connection: connection,\n requested_token_type:\n \"http://auth0.com/oauth/token-type/federated-connection-access-token\",\n };\n\n const res = await fetch(`https://${this.auth0.domain}/oauth/token`, {\n method: \"POST\",\n headers: { \"Content-Type\": \"application/json\" },\n body: JSON.stringify(exchangeParams),\n });\n\n if (!res.ok) {\n return;\n }\n\n const tokenResponse: TokenResponse = await res.json();\n return tokenResponse;\n }\n\n protected async getAccessToken(\n ...toolContext: ToolExecuteArgs\n ): Promise<TokenResponse | undefined> {\n let tokenResponse: TokenResponse | undefined;\n if (typeof this.params.refreshToken === \"function\") {\n tokenResponse = await this.getAccessTokenImpl(...toolContext);\n } else {\n tokenResponse = await resolveParameter(\n this.params.accessToken!,\n toolContext\n );\n }\n this.validateToken(tokenResponse);\n return tokenResponse;\n }\n\n protected async getRefreshToken(...toolContext: ToolExecuteArgs) {\n return await resolveParameter(this.params.refreshToken, toolContext);\n }\n\n /**\n *\n * Wraps the execute method of an AI tool to handle Federated Connections authorization.\n *\n * @param getContext - A function that returns the context of the tool execution.\n * @param execute - The tool execute method.\n * @returns The wrapped execute method.\n */\n protect(\n getContext: (...args: ToolExecuteArgs) => any,\n execute: (...args: ToolExecuteArgs) => any\n ): (...args: ToolExecuteArgs) => any {\n return async (...args: ToolExecuteArgs) => {\n const asyncStore: AsyncStorageValue<any> = {\n context: await getContext(...args),\n scopes: await resolveParameter(this.params.scopes, args),\n connection: await resolveParameter(this.params.connection, args),\n };\n\n if (asyncLocalStorage.getStore()) {\n throw new Error(\n \"Cannot nest tool calls that require federated connection authorization.\"\n );\n }\n\n return asyncLocalStorage.run(asyncStore, async () => {\n try {\n const tokenResponse = await this.getAccessToken(...args);\n asyncStore.accessToken = tokenResponse!.access_token;\n return await execute(...args);\n } catch (err) {\n if (err instanceof FederatedConnectionError) {\n const interrupt = new FederatedConnectionInterrupt(\n err.message,\n asyncStore.connection,\n asyncStore.scopes,\n asyncStore.scopes\n );\n return this.handleAuthorizationInterrupts(interrupt);\n }\n if (err instanceof Auth0Interrupt) {\n return this.handleAuthorizationInterrupts(err);\n }\n throw err;\n }\n });\n };\n }\n}\n"]}
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.buildOpenFgaClient = buildOpenFgaClient;
|
|
4
|
+
const sdk_1 = require("@openfga/sdk");
|
|
5
|
+
function buildOpenFgaClient(fgaClientParams) {
|
|
6
|
+
var _a, _b, _c, _d, _e;
|
|
7
|
+
return new sdk_1.OpenFgaClient({
|
|
8
|
+
apiUrl: (fgaClientParams === null || fgaClientParams === void 0 ? void 0 : fgaClientParams.apiUrl) ||
|
|
9
|
+
process.env.FGA_API_URL ||
|
|
10
|
+
"https://api.us1.fga.dev",
|
|
11
|
+
storeId: (fgaClientParams === null || fgaClientParams === void 0 ? void 0 : fgaClientParams.storeId) || process.env.FGA_STORE_ID,
|
|
12
|
+
credentials: {
|
|
13
|
+
method: ((_a = fgaClientParams === null || fgaClientParams === void 0 ? void 0 : fgaClientParams.credentials) === null || _a === void 0 ? void 0 : _a.method) ||
|
|
14
|
+
sdk_1.CredentialsMethod.ClientCredentials,
|
|
15
|
+
config: {
|
|
16
|
+
apiTokenIssuer: ((_b = fgaClientParams === null || fgaClientParams === void 0 ? void 0 : fgaClientParams.credentials) === null || _b === void 0 ? void 0 : _b.config.apiTokenIssuer) ||
|
|
17
|
+
process.env.FGA_API_TOKEN_ISSUER ||
|
|
18
|
+
"auth.fga.dev",
|
|
19
|
+
apiAudience: ((_c = fgaClientParams === null || fgaClientParams === void 0 ? void 0 : fgaClientParams.credentials) === null || _c === void 0 ? void 0 : _c.config.apiAudience) ||
|
|
20
|
+
process.env.FGA_API_AUDIENCE ||
|
|
21
|
+
"https://api.us1.fga.dev/",
|
|
22
|
+
clientId: ((_d = fgaClientParams === null || fgaClientParams === void 0 ? void 0 : fgaClientParams.credentials) === null || _d === void 0 ? void 0 : _d.config.clientId) ||
|
|
23
|
+
process.env.FGA_CLIENT_ID,
|
|
24
|
+
clientSecret: ((_e = fgaClientParams === null || fgaClientParams === void 0 ? void 0 : fgaClientParams.credentials) === null || _e === void 0 ? void 0 : _e.config.clientSecret) ||
|
|
25
|
+
process.env.FGA_CLIENT_SECRET,
|
|
26
|
+
},
|
|
27
|
+
},
|
|
28
|
+
});
|
|
29
|
+
}
|
|
30
|
+
//# sourceMappingURL=fga-client.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"fga-client.js","sourceRoot":"","sources":["../../../../src/authorizers/fga/fga-client.ts"],"names":[],"mappings":";;AAgBA,gDA+BC;AA/CD,sCAAgE;AAgBhE,SAAgB,kBAAkB,CAChC,eAAwC;;IAExC,OAAO,IAAI,mBAAa,CAAC;QACvB,MAAM,EACJ,CAAA,eAAe,aAAf,eAAe,uBAAf,eAAe,CAAE,MAAM;YACvB,OAAO,CAAC,GAAG,CAAC,WAAW;YACvB,yBAAyB;QAC3B,OAAO,EAAE,CAAA,eAAe,aAAf,eAAe,uBAAf,eAAe,CAAE,OAAO,KAAI,OAAO,CAAC,GAAG,CAAC,YAAa;QAC9D,WAAW,EAAE;YACX,MAAM,EACJ,CAAA,MAAA,eAAe,aAAf,eAAe,uBAAf,eAAe,CAAE,WAAW,0CAAE,MAAM;gBACpC,uBAAiB,CAAC,iBAAiB;YACrC,MAAM,EAAE;gBACN,cAAc,EACZ,CAAA,MAAA,eAAe,aAAf,eAAe,uBAAf,eAAe,CAAE,WAAW,0CAAE,MAAM,CAAC,cAAc;oBACnD,OAAO,CAAC,GAAG,CAAC,oBAAoB;oBAChC,cAAc;gBAChB,WAAW,EACT,CAAA,MAAA,eAAe,aAAf,eAAe,uBAAf,eAAe,CAAE,WAAW,0CAAE,MAAM,CAAC,WAAW;oBAChD,OAAO,CAAC,GAAG,CAAC,gBAAgB;oBAC5B,0BAA0B;gBAC5B,QAAQ,EACN,CAAA,MAAA,eAAe,aAAf,eAAe,uBAAf,eAAe,CAAE,WAAW,0CAAE,MAAM,CAAC,QAAQ;oBAC7C,OAAO,CAAC,GAAG,CAAC,aAAc;gBAC5B,YAAY,EACV,CAAA,MAAA,eAAe,aAAf,eAAe,uBAAf,eAAe,CAAE,WAAW,0CAAE,MAAM,CAAC,YAAY;oBACjD,OAAO,CAAC,GAAG,CAAC,iBAAkB;aACjC;SACF;KACF,CAAC,CAAC;AACL,CAAC","sourcesContent":["import { CredentialsMethod, OpenFgaClient } from \"@openfga/sdk\";\n\nexport type FGAClientParams = {\n apiUrl?: string;\n storeId?: string;\n credentials?: {\n method: any;\n config: {\n apiTokenIssuer: string;\n apiAudience: string;\n clientId: string;\n clientSecret: string;\n };\n };\n};\n\nexport function buildOpenFgaClient(\n fgaClientParams?: FGAClientParams | null\n): OpenFgaClient {\n return new OpenFgaClient({\n apiUrl:\n fgaClientParams?.apiUrl ||\n process.env.FGA_API_URL ||\n \"https://api.us1.fga.dev\",\n storeId: fgaClientParams?.storeId || process.env.FGA_STORE_ID!,\n credentials: {\n method:\n fgaClientParams?.credentials?.method ||\n CredentialsMethod.ClientCredentials,\n config: {\n apiTokenIssuer:\n fgaClientParams?.credentials?.config.apiTokenIssuer ||\n process.env.FGA_API_TOKEN_ISSUER ||\n \"auth.fga.dev\",\n apiAudience:\n fgaClientParams?.credentials?.config.apiAudience ||\n process.env.FGA_API_AUDIENCE ||\n \"https://api.us1.fga.dev/\",\n clientId:\n fgaClientParams?.credentials?.config.clientId ||\n process.env.FGA_CLIENT_ID!,\n clientSecret:\n fgaClientParams?.credentials?.config.clientSecret ||\n process.env.FGA_CLIENT_SECRET!,\n },\n },\n });\n}\n"]}
|
|
@@ -0,0 +1,94 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.FGAFilter = void 0;
|
|
4
|
+
const sdk_1 = require("@openfga/sdk");
|
|
5
|
+
const fga_client_1 = require("./fga-client");
|
|
6
|
+
/**
|
|
7
|
+
* A filter that allows filtering documents based on access control checks
|
|
8
|
+
* using OpenFGA. This class performs batch checks on passed documents,
|
|
9
|
+
* returning only the ones that pass the specified access criteria.
|
|
10
|
+
*
|
|
11
|
+
* @remarks
|
|
12
|
+
* The FGAFilter requires a buildQuery function to specify how access checks
|
|
13
|
+
* are formed for each document, the checks are executed via an OpenFGA client
|
|
14
|
+
* or equivalent mechanism. The checks are then mapped back to their corresponding
|
|
15
|
+
* documents to filter out those for which access is denied.
|
|
16
|
+
*
|
|
17
|
+
* @example
|
|
18
|
+
* ```ts
|
|
19
|
+
* const filter = FGAFilter.create({
|
|
20
|
+
* buildQuery: (doc) => ({
|
|
21
|
+
* user: `user:${user}`,
|
|
22
|
+
* object: `doc:${doc.metadata.id}`,
|
|
23
|
+
* relation: "viewer",
|
|
24
|
+
* }),
|
|
25
|
+
* });
|
|
26
|
+
* ```
|
|
27
|
+
*/
|
|
28
|
+
class FGAFilter {
|
|
29
|
+
constructor({ buildQuery, consistency }, fgaClientParams) {
|
|
30
|
+
this.buildQuery = buildQuery;
|
|
31
|
+
this.consistency = consistency || sdk_1.ConsistencyPreference.HigherConsistency;
|
|
32
|
+
this.fgaClient = (0, fga_client_1.buildOpenFgaClient)(fgaClientParams);
|
|
33
|
+
}
|
|
34
|
+
/**
|
|
35
|
+
* Creates a new FGAFilter instance using the given arguments and optional OpenFgaClient.
|
|
36
|
+
*
|
|
37
|
+
* @param args - @FGAFilterArgs
|
|
38
|
+
* @param args.buildQuery - A function to generate access check requests for each document.
|
|
39
|
+
* @param args.consistency - Optional - The consistency preference for the OpenFGA client.
|
|
40
|
+
* @param fgaClientParams - Optional - OpenFgaClient configuration to execute checks against.
|
|
41
|
+
* @returns A newly created FGAFilter instance configured with the provided arguments.
|
|
42
|
+
*/
|
|
43
|
+
static create(args, fgaClientParams) {
|
|
44
|
+
return new FGAFilter(args, fgaClientParams);
|
|
45
|
+
}
|
|
46
|
+
/**
|
|
47
|
+
* Filters documents based on the provided query parameters, processes
|
|
48
|
+
* them through a checker function,
|
|
49
|
+
* and filters the documents based on permissions.
|
|
50
|
+
*
|
|
51
|
+
* @param params - The query parameters used to retrieve nodes.
|
|
52
|
+
* @returns A promise that resolves to an array of documents that have passed the permission checks.
|
|
53
|
+
*/
|
|
54
|
+
async filter(documents) {
|
|
55
|
+
const { checks, documentToObject } = documents.reduce((acc, doc) => {
|
|
56
|
+
const check = this.buildQuery(doc);
|
|
57
|
+
const checkKey = this.getCheckKey(check);
|
|
58
|
+
acc.documentToObject.set(doc, checkKey);
|
|
59
|
+
// Skip duplicate checks for same user, object, and relation
|
|
60
|
+
if (!acc.seenChecks.has(checkKey)) {
|
|
61
|
+
acc.seenChecks.add(checkKey);
|
|
62
|
+
acc.checks.push(check);
|
|
63
|
+
}
|
|
64
|
+
return acc;
|
|
65
|
+
}, {
|
|
66
|
+
checks: [],
|
|
67
|
+
documentToObject: new Map(),
|
|
68
|
+
seenChecks: new Set(),
|
|
69
|
+
});
|
|
70
|
+
const permissionsMap = await this.checkPermissions(checks);
|
|
71
|
+
return documents.filter((d) => permissionsMap.get(documentToObject.get(d) || "") === true);
|
|
72
|
+
}
|
|
73
|
+
/**
|
|
74
|
+
* Checks permissions for a list of client requests.
|
|
75
|
+
*
|
|
76
|
+
* @param checks - An array of `ClientBatchCheckItem` objects representing the permissions to be checked.
|
|
77
|
+
* @returns A promise that resolves to a `Map` where the keys are object identifiers and the values are booleans indicating whether the permission is allowed.
|
|
78
|
+
*/
|
|
79
|
+
async checkPermissions(checks) {
|
|
80
|
+
const response = await this.fgaClient.batchCheck({ checks }, {
|
|
81
|
+
consistency: this.consistency,
|
|
82
|
+
});
|
|
83
|
+
return response.result.reduce((permissionMap, result) => {
|
|
84
|
+
const checkKey = this.getCheckKey(result.request);
|
|
85
|
+
permissionMap.set(checkKey, result.allowed || false);
|
|
86
|
+
return permissionMap;
|
|
87
|
+
}, new Map());
|
|
88
|
+
}
|
|
89
|
+
getCheckKey(check) {
|
|
90
|
+
return `${check.user}|${check.object}|${check.relation}`;
|
|
91
|
+
}
|
|
92
|
+
}
|
|
93
|
+
exports.FGAFilter = FGAFilter;
|
|
94
|
+
//# sourceMappingURL=fga-filter.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"fga-filter.js","sourceRoot":"","sources":["../../../../src/authorizers/fga/fga-filter.ts"],"names":[],"mappings":";;;AAAA,sCAIsB;AAEtB,6CAAmE;AAWnE;;;;;;;;;;;;;;;;;;;;;GAqBG;AACH,MAAa,SAAS;IAKpB,YACE,EAAE,UAAU,EAAE,WAAW,EAAoB,EAC7C,eAAiC;QAEjC,IAAI,CAAC,UAAU,GAAG,UAAU,CAAC;QAC7B,IAAI,CAAC,WAAW,GAAG,WAAW,IAAI,2BAAqB,CAAC,iBAAiB,CAAC;QAC1E,IAAI,CAAC,SAAS,GAAG,IAAA,+BAAkB,EAAC,eAAe,CAAC,CAAC;IACvD,CAAC;IAED;;;;;;;;OAQG;IACH,MAAM,CAAC,MAAM,CACX,IAAsB,EACtB,eAAiC;QAEjC,OAAO,IAAI,SAAS,CAAC,IAAI,EAAE,eAAe,CAAC,CAAC;IAC9C,CAAC;IAED;;;;;;;OAOG;IACH,KAAK,CAAC,MAAM,CAAC,SAAc;QACzB,MAAM,EAAE,MAAM,EAAE,gBAAgB,EAAE,GAAG,SAAS,CAAC,MAAM,CACnD,CAAC,GAAG,EAAE,GAAG,EAAE,EAAE;YACX,MAAM,KAAK,GAAG,IAAI,CAAC,UAAU,CAAC,GAAG,CAAC,CAAC;YACnC,MAAM,QAAQ,GAAG,IAAI,CAAC,WAAW,CAAC,KAAK,CAAC,CAAC;YACzC,GAAG,CAAC,gBAAgB,CAAC,GAAG,CAAC,GAAG,EAAE,QAAQ,CAAC,CAAC;YACxC,4DAA4D;YAC5D,IAAI,CAAC,GAAG,CAAC,UAAU,CAAC,GAAG,CAAC,QAAQ,CAAC,EAAE,CAAC;gBAClC,GAAG,CAAC,UAAU,CAAC,GAAG,CAAC,QAAQ,CAAC,CAAC;gBAC7B,GAAG,CAAC,MAAM,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC;YACzB,CAAC;YACD,OAAO,GAAG,CAAC;QACb,CAAC,EACD;YACE,MAAM,EAAE,EAA4B;YACpC,gBAAgB,EAAE,IAAI,GAAG,EAAa;YACtC,UAAU,EAAE,IAAI,GAAG,EAAU;SAC9B,CACF,CAAC;QAEF,MAAM,cAAc,GAAG,MAAM,IAAI,CAAC,gBAAgB,CAAC,MAAM,CAAC,CAAC;QAE3D,OAAO,SAAS,CAAC,MAAM,CACrB,CAAC,CAAC,EAAE,EAAE,CAAC,cAAc,CAAC,GAAG,CAAC,gBAAgB,CAAC,GAAG,CAAC,CAAC,CAAC,IAAI,EAAE,CAAC,KAAK,IAAI,CAClE,CAAC;IACJ,CAAC;IAED;;;;;OAKG;IACK,KAAK,CAAC,gBAAgB,CAC5B,MAA8B;QAE9B,MAAM,QAAQ,GAAG,MAAM,IAAI,CAAC,SAAS,CAAC,UAAU,CAC9C,EAAE,MAAM,EAAE,EACV;YACE,WAAW,EAAE,IAAI,CAAC,WAAW;SAC9B,CACF,CAAC;QAEF,OAAO,QAAQ,CAAC,MAAM,CAAC,MAAM,CAC3B,CAAC,aAAmC,EAAE,MAAM,EAAE,EAAE;YAC9C,MAAM,QAAQ,GAAG,IAAI,CAAC,WAAW,CAAC,MAAM,CAAC,OAAO,CAAC,CAAC;YAClD,aAAa,CAAC,GAAG,CAAC,QAAQ,EAAE,MAAM,CAAC,OAAO,IAAI,KAAK,CAAC,CAAC;YACrD,OAAO,aAAa,CAAC;QACvB,CAAC,EACD,IAAI,GAAG,EAAmB,CAC3B,CAAC;IACJ,CAAC;IAEO,WAAW,CAAC,KAA2B;QAC7C,OAAO,GAAG,KAAK,CAAC,IAAI,IAAI,KAAK,CAAC,MAAM,IAAI,KAAK,CAAC,QAAQ,EAAE,CAAC;IAC3D,CAAC;CACF;AA9FD,8BA8FC","sourcesContent":["import {\n ClientBatchCheckItem,\n ConsistencyPreference,\n OpenFgaClient,\n} from \"@openfga/sdk\";\n\nimport { buildOpenFgaClient, FGAClientParams } from \"./fga-client\";\n\nexport type FGAFilterCheckerFn<T extends Record<string, any>> = (\n doc: T\n) => ClientBatchCheckItem;\n\nexport type FGAFilterArgs<T extends Record<string, any>> = {\n buildQuery: FGAFilterCheckerFn<T>;\n consistency?: ConsistencyPreference;\n};\n\n/**\n * A filter that allows filtering documents based on access control checks\n * using OpenFGA. This class performs batch checks on passed documents,\n * returning only the ones that pass the specified access criteria.\n *\n * @remarks\n * The FGAFilter requires a buildQuery function to specify how access checks\n * are formed for each document, the checks are executed via an OpenFGA client\n * or equivalent mechanism. The checks are then mapped back to their corresponding\n * documents to filter out those for which access is denied.\n *\n * @example\n * ```ts\n * const filter = FGAFilter.create({\n * buildQuery: (doc) => ({\n * user: `user:${user}`,\n * object: `doc:${doc.metadata.id}`,\n * relation: \"viewer\",\n * }),\n * });\n * ```\n */\nexport class FGAFilter<T extends Record<string, any>> {\n private buildQuery: FGAFilterCheckerFn<T>;\n private consistency: ConsistencyPreference;\n private fgaClient: OpenFgaClient;\n\n private constructor(\n { buildQuery, consistency }: FGAFilterArgs<T>,\n fgaClientParams?: FGAClientParams\n ) {\n this.buildQuery = buildQuery;\n this.consistency = consistency || ConsistencyPreference.HigherConsistency;\n this.fgaClient = buildOpenFgaClient(fgaClientParams);\n }\n\n /**\n * Creates a new FGAFilter instance using the given arguments and optional OpenFgaClient.\n *\n * @param args - @FGAFilterArgs\n * @param args.buildQuery - A function to generate access check requests for each document.\n * @param args.consistency - Optional - The consistency preference for the OpenFGA client.\n * @param fgaClientParams - Optional - OpenFgaClient configuration to execute checks against.\n * @returns A newly created FGAFilter instance configured with the provided arguments.\n */\n static create<T extends Record<string, any>>(\n args: FGAFilterArgs<T>,\n fgaClientParams?: FGAClientParams\n ): FGAFilter<T> {\n return new FGAFilter(args, fgaClientParams);\n }\n\n /**\n * Filters documents based on the provided query parameters, processes\n * them through a checker function,\n * and filters the documents based on permissions.\n *\n * @param params - The query parameters used to retrieve nodes.\n * @returns A promise that resolves to an array of documents that have passed the permission checks.\n */\n async filter(documents: T[]): Promise<T[]> {\n const { checks, documentToObject } = documents.reduce(\n (acc, doc) => {\n const check = this.buildQuery(doc);\n const checkKey = this.getCheckKey(check);\n acc.documentToObject.set(doc, checkKey);\n // Skip duplicate checks for same user, object, and relation\n if (!acc.seenChecks.has(checkKey)) {\n acc.seenChecks.add(checkKey);\n acc.checks.push(check);\n }\n return acc;\n },\n {\n checks: [] as ClientBatchCheckItem[],\n documentToObject: new Map<T, string>(),\n seenChecks: new Set<string>(),\n }\n );\n\n const permissionsMap = await this.checkPermissions(checks);\n\n return documents.filter(\n (d) => permissionsMap.get(documentToObject.get(d) || \"\") === true\n );\n }\n\n /**\n * Checks permissions for a list of client requests.\n *\n * @param checks - An array of `ClientBatchCheckItem` objects representing the permissions to be checked.\n * @returns A promise that resolves to a `Map` where the keys are object identifiers and the values are booleans indicating whether the permission is allowed.\n */\n private async checkPermissions(\n checks: ClientBatchCheckItem[]\n ): Promise<Map<string, boolean>> {\n const response = await this.fgaClient.batchCheck(\n { checks },\n {\n consistency: this.consistency,\n }\n );\n\n return response.result.reduce(\n (permissionMap: Map<string, boolean>, result) => {\n const checkKey = this.getCheckKey(result.request);\n permissionMap.set(checkKey, result.allowed || false);\n return permissionMap;\n },\n new Map<string, boolean>()\n );\n }\n\n private getCheckKey(check: ClientBatchCheckItem): string {\n return `${check.user}|${check.object}|${check.relation}`;\n }\n}\n"]}
|
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.FGAAuthorizerBase = void 0;
|
|
4
|
+
const sdk_1 = require("@openfga/sdk");
|
|
5
|
+
const fga_client_1 = require("./fga-client");
|
|
6
|
+
class FGAAuthorizerBase {
|
|
7
|
+
constructor(fgaClientParams, authorizeOptions) {
|
|
8
|
+
this.authorizeOptions = authorizeOptions;
|
|
9
|
+
this.fgaClient = (0, fga_client_1.buildOpenFgaClient)(fgaClientParams);
|
|
10
|
+
}
|
|
11
|
+
/**
|
|
12
|
+
*
|
|
13
|
+
* Wraps the execute method of an AI tool to handle FGA authorization.
|
|
14
|
+
*
|
|
15
|
+
* @param execute - The tool execute method.
|
|
16
|
+
* @returns The wrapped execute method.
|
|
17
|
+
*/
|
|
18
|
+
protect(execute) {
|
|
19
|
+
return async (...args) => {
|
|
20
|
+
const check = await this.authorizeOptions.buildQuery(...args);
|
|
21
|
+
const { allowed } = await this.fgaClient.check(check, {
|
|
22
|
+
consistency: sdk_1.ConsistencyPreference.HigherConsistency,
|
|
23
|
+
});
|
|
24
|
+
if (!allowed) {
|
|
25
|
+
if (typeof this.authorizeOptions.onUnauthorized === "function") {
|
|
26
|
+
return this.authorizeOptions.onUnauthorized(...args);
|
|
27
|
+
}
|
|
28
|
+
else {
|
|
29
|
+
return "The user is not allowed to perform the action.";
|
|
30
|
+
}
|
|
31
|
+
}
|
|
32
|
+
return execute(...args);
|
|
33
|
+
};
|
|
34
|
+
}
|
|
35
|
+
}
|
|
36
|
+
exports.FGAAuthorizerBase = FGAAuthorizerBase;
|
|
37
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../../../src/authorizers/fga/index.ts"],"names":[],"mappings":";;;AAAA,sCAIsB;AAEtB,6CAAmE;AASnE,MAAa,iBAAiB;IAG5B,YACE,eAAmD,EAC3C,gBAAuD;QAAvD,qBAAgB,GAAhB,gBAAgB,CAAuC;QAE/D,IAAI,CAAC,SAAS,GAAG,IAAA,+BAAkB,EAAC,eAAe,CAAC,CAAC;IACvD,CAAC;IAED;;;;;;OAMG;IACH,OAAO,CACL,OAA0C;QAE1C,OAAO,KAAK,EAAE,GAAG,IAAqB,EAAE,EAAE;YACxC,MAAM,KAAK,GAAG,MAAM,IAAI,CAAC,gBAAgB,CAAC,UAAU,CAAC,GAAG,IAAI,CAAC,CAAC;YAC9D,MAAM,EAAE,OAAO,EAAE,GAAG,MAAM,IAAI,CAAC,SAAS,CAAC,KAAK,CAAC,KAAK,EAAE;gBACpD,WAAW,EAAE,2BAAqB,CAAC,iBAAiB;aACrD,CAAC,CAAC;YACH,IAAI,CAAC,OAAO,EAAE,CAAC;gBACb,IAAI,OAAO,IAAI,CAAC,gBAAgB,CAAC,cAAc,KAAK,UAAU,EAAE,CAAC;oBAC/D,OAAO,IAAI,CAAC,gBAAgB,CAAC,cAAc,CAAC,GAAG,IAAI,CAAC,CAAC;gBACvD,CAAC;qBAAM,CAAC;oBACN,OAAO,gDAAgD,CAAC;gBAC1D,CAAC;YACH,CAAC;YACD,OAAO,OAAO,CAAC,GAAG,IAAI,CAAC,CAAC;QAC1B,CAAC,CAAC;IACJ,CAAC;CACF;AAnCD,8CAmCC","sourcesContent":["import {\n ClientCheckRequest,\n ConsistencyPreference,\n OpenFgaClient,\n} from \"@openfga/sdk\";\n\nimport { buildOpenFgaClient, FGAClientParams } from \"./fga-client\";\n\nexport type { FGAClientParams };\n\nexport type FGAAuthorizerOptions<ToolExecuteArgs extends any[]> = {\n buildQuery: (...args: ToolExecuteArgs) => Promise<ClientCheckRequest>;\n onUnauthorized?: (...args: ToolExecuteArgs) => any;\n};\n\nexport class FGAAuthorizerBase<ToolExecuteArgs extends any[]> {\n fgaClient: OpenFgaClient;\n\n constructor(\n fgaClientParams: FGAClientParams | undefined | null,\n private authorizeOptions: FGAAuthorizerOptions<ToolExecuteArgs>\n ) {\n this.fgaClient = buildOpenFgaClient(fgaClientParams);\n }\n\n /**\n *\n * Wraps the execute method of an AI tool to handle FGA authorization.\n *\n * @param execute - The tool execute method.\n * @returns The wrapped execute method.\n */\n protect(\n execute: (...args: ToolExecuteArgs) => any\n ): (...args: ToolExecuteArgs) => any {\n return async (...args: ToolExecuteArgs) => {\n const check = await this.authorizeOptions.buildQuery(...args);\n const { allowed } = await this.fgaClient.check(check, {\n consistency: ConsistencyPreference.HigherConsistency,\n });\n if (!allowed) {\n if (typeof this.authorizeOptions.onUnauthorized === \"function\") {\n return this.authorizeOptions.onUnauthorized(...args);\n } else {\n return \"The user is not allowed to perform the action.\";\n }\n }\n return execute(...args);\n };\n }\n}\n"]}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../../src/authorizers/index.ts"],"names":[],"mappings":"","sourcesContent":["import { AuthenticationClientOptions } from \"auth0\";\nimport * as jose from \"jose\";\n\nexport type AuthParams = {\n allowed?: boolean;\n accessToken?: string;\n claims?: jose.JWTPayload;\n};\n\nexport type ToolWithAuthHandler<I, O, C> = (\n authParams: AuthParams,\n input: I,\n config?: C\n) => Promise<O>;\n\nexport type AuthorizerParams = Omit<\n AuthenticationClientOptions,\n \"domain\" | \"clientId\"\n> & {\n domain?: string;\n clientId?: string;\n};\n"]}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"credentials.js","sourceRoot":"","sources":["../../src/credentials.ts"],"names":[],"mappings":"","sourcesContent":["export interface Credential {\n type: string;\n value: string;\n}\n\nexport interface Credentials {\n idToken?: Credential;\n accessToken: Credential;\n refreshToken?: Credential;\n}\n"]}
|
|
@@ -0,0 +1,46 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.AuthorizationPollingError = exports.AuthorizationRequired = exports.AuthorizationPending = exports.AuthorizationRequestExpiredError = exports.UserDoesNotHavePushNotificationsError = exports.AccessDeniedError = void 0;
|
|
4
|
+
class AccessDeniedError extends Error {
|
|
5
|
+
constructor(message) {
|
|
6
|
+
super(message);
|
|
7
|
+
this.name = AccessDeniedError.name;
|
|
8
|
+
}
|
|
9
|
+
}
|
|
10
|
+
exports.AccessDeniedError = AccessDeniedError;
|
|
11
|
+
class UserDoesNotHavePushNotificationsError extends Error {
|
|
12
|
+
constructor(message) {
|
|
13
|
+
super(message);
|
|
14
|
+
this.name = UserDoesNotHavePushNotificationsError.name;
|
|
15
|
+
}
|
|
16
|
+
}
|
|
17
|
+
exports.UserDoesNotHavePushNotificationsError = UserDoesNotHavePushNotificationsError;
|
|
18
|
+
class AuthorizationRequestExpiredError extends Error {
|
|
19
|
+
constructor(message) {
|
|
20
|
+
super(message);
|
|
21
|
+
this.name = AuthorizationRequestExpiredError.name;
|
|
22
|
+
}
|
|
23
|
+
}
|
|
24
|
+
exports.AuthorizationRequestExpiredError = AuthorizationRequestExpiredError;
|
|
25
|
+
class AuthorizationPending extends Error {
|
|
26
|
+
constructor(message) {
|
|
27
|
+
super(message);
|
|
28
|
+
this.name = AuthorizationPending.name;
|
|
29
|
+
}
|
|
30
|
+
}
|
|
31
|
+
exports.AuthorizationPending = AuthorizationPending;
|
|
32
|
+
class AuthorizationRequired extends Error {
|
|
33
|
+
constructor(message) {
|
|
34
|
+
super(message);
|
|
35
|
+
this.name = AuthorizationRequired.name;
|
|
36
|
+
}
|
|
37
|
+
}
|
|
38
|
+
exports.AuthorizationRequired = AuthorizationRequired;
|
|
39
|
+
class AuthorizationPollingError extends Error {
|
|
40
|
+
constructor(message) {
|
|
41
|
+
super(message);
|
|
42
|
+
this.name = AuthorizationPollingError.name;
|
|
43
|
+
}
|
|
44
|
+
}
|
|
45
|
+
exports.AuthorizationPollingError = AuthorizationPollingError;
|
|
46
|
+
//# sourceMappingURL=errors.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"errors.js","sourceRoot":"","sources":["../../src/errors.ts"],"names":[],"mappings":";;;AAAA,MAAa,iBAAkB,SAAQ,KAAK;IAC1C,YAAY,OAAe;QACzB,KAAK,CAAC,OAAO,CAAC,CAAC;QACf,IAAI,CAAC,IAAI,GAAG,iBAAiB,CAAC,IAAI,CAAC;IACrC,CAAC;CACF;AALD,8CAKC;AAED,MAAa,qCAAsC,SAAQ,KAAK;IAC9D,YAAY,OAAe;QACzB,KAAK,CAAC,OAAO,CAAC,CAAC;QACf,IAAI,CAAC,IAAI,GAAG,qCAAqC,CAAC,IAAI,CAAC;IACzD,CAAC;CACF;AALD,sFAKC;AAED,MAAa,gCAAiC,SAAQ,KAAK;IACzD,YAAY,OAAe;QACzB,KAAK,CAAC,OAAO,CAAC,CAAC;QACf,IAAI,CAAC,IAAI,GAAG,gCAAgC,CAAC,IAAI,CAAC;IACpD,CAAC;CACF;AALD,4EAKC;AAED,MAAa,oBAAqB,SAAQ,KAAK;IAC7C,YAAY,OAAe;QACzB,KAAK,CAAC,OAAO,CAAC,CAAC;QACf,IAAI,CAAC,IAAI,GAAG,oBAAoB,CAAC,IAAI,CAAC;IACxC,CAAC;CACF;AALD,oDAKC;AAED,MAAa,qBAAsB,SAAQ,KAAK;IAC9C,YAAY,OAAe;QACzB,KAAK,CAAC,OAAO,CAAC,CAAC;QACf,IAAI,CAAC,IAAI,GAAG,qBAAqB,CAAC,IAAI,CAAC;IACzC,CAAC;CACF;AALD,sDAKC;AAED,MAAa,yBAA0B,SAAQ,KAAK;IAClD,YAAY,OAAe;QACzB,KAAK,CAAC,OAAO,CAAC,CAAC;QACf,IAAI,CAAC,IAAI,GAAG,yBAAyB,CAAC,IAAI,CAAC;IAC7C,CAAC;CACF;AALD,8DAKC","sourcesContent":["export class AccessDeniedError extends Error {\n constructor(message: string) {\n super(message);\n this.name = AccessDeniedError.name;\n }\n}\n\nexport class UserDoesNotHavePushNotificationsError extends Error {\n constructor(message: string) {\n super(message);\n this.name = UserDoesNotHavePushNotificationsError.name;\n }\n}\n\nexport class AuthorizationRequestExpiredError extends Error {\n constructor(message: string) {\n super(message);\n this.name = AuthorizationRequestExpiredError.name;\n }\n}\n\nexport class AuthorizationPending extends Error {\n constructor(message: string) {\n super(message);\n this.name = AuthorizationPending.name;\n }\n}\n\nexport class AuthorizationRequired extends Error {\n constructor(message: string) {\n super(message);\n this.name = AuthorizationRequired.name;\n }\n}\n\nexport class AuthorizationPollingError extends Error {\n constructor(message: string) {\n super(message);\n this.name = AuthorizationPollingError.name;\n }\n}\n"]}
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
|
|
3
|
+
if (k2 === undefined) k2 = k;
|
|
4
|
+
var desc = Object.getOwnPropertyDescriptor(m, k);
|
|
5
|
+
if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
|
|
6
|
+
desc = { enumerable: true, get: function() { return m[k]; } };
|
|
7
|
+
}
|
|
8
|
+
Object.defineProperty(o, k2, desc);
|
|
9
|
+
}) : (function(o, m, k, k2) {
|
|
10
|
+
if (k2 === undefined) k2 = k;
|
|
11
|
+
o[k2] = m[k];
|
|
12
|
+
}));
|
|
13
|
+
var __exportStar = (this && this.__exportStar) || function(m, exports) {
|
|
14
|
+
for (var p in m) if (p !== "default" && !Object.prototype.hasOwnProperty.call(exports, p)) __createBinding(exports, m, p);
|
|
15
|
+
};
|
|
16
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
17
|
+
__exportStar(require("./authorizers/device-authorizer"), exports);
|
|
18
|
+
__exportStar(require("./errors"), exports);
|
|
19
|
+
__exportStar(require("./authorizers/fga/fga-filter"), exports);
|
|
20
|
+
__exportStar(require("./authorizers/fga/fga-client"), exports);
|
|
21
|
+
__exportStar(require("./parameters"), exports);
|
|
22
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/index.ts"],"names":[],"mappings":";;;;;;;;;;;;;;;;AAEA,kEAAgD;AAChD,2CAAyB;AAEzB,+DAA6C;AAC7C,+DAA6C;AAC7C,+CAA6B","sourcesContent":["export type { AuthParams, AuthorizerParams } from \"./authorizers\";\nexport type * from \"./credentials\";\nexport * from \"./authorizers/device-authorizer\";\nexport * from \"./errors\";\nexport type { TokenResponse } from \"./TokenResponse\";\nexport * from \"./authorizers/fga/fga-filter\";\nexport * from \"./authorizers/fga/fga-client\";\nexport * from \"./parameters\";\n"]}
|