From 1c635ca3c60914844971bb9be40db4db7076ba2a Mon Sep 17 00:00:00 2001 From: Ryan Quinn Date: Fri, 15 Nov 2024 10:51:27 -0600 Subject: [PATCH 1/5] docs: missing import in ClientCredentials example --- README.md | 8 +++--- api.ts | 40 +++++++++++++++--------------- client.ts | 2 ++ configuration.ts | 7 +++--- docs/opentelemetry.md | 8 +++--- example/README.md | 4 +-- telemetry/attributes.ts | 12 --------- tests/telemetry/attributes.test.ts | 16 ------------ 8 files changed, 36 insertions(+), 61 deletions(-) diff --git a/README.md b/README.md index 427729b..211d4a3 100644 --- a/README.md +++ b/README.md @@ -87,7 +87,7 @@ yarn add @openfga/sdk [Learn how to initialize your SDK](https://openfga.dev/docs/getting-started/setup-sdk-client) -We strongly recommend you initialize the `OpenFgaClient` only once and then re-use it throughout your app, otherwise you will incur the cost of having to re-initialize multiple times or at every request, the cost of reduced connection pooling and re-use, and would be particularly costly in the client credentials flow, as that flow will be performed on every request. +We strongly recommend you initialize the `OpenFgaClient` only once and then re-use it throughout your app, otherwise you will incur the cost of having to re-initialize multiple times or at every request, the cost of reduced connection pooling and re-use, and would be particularly costly in the client credentials flow, as that flow will be preformed on every request. > The `OpenFgaClient` will by default retry API requests up to 15 times on 429 and 5xx errors. @@ -106,7 +106,7 @@ const fgaClient = new OpenFgaClient({ #### API Token ```javascript -const { OpenFgaClient } = require('@openfga/sdk'); // OR import { OpenFgaClient } from '@openfga/sdk'; +const { OpenFgaClient, CredentialsMethod } = require('@openfga/sdk'); // OR import { OpenFgaClient, CredentialsMethod } from '@openfga/sdk'; const fgaClient = new OpenFgaClient({ apiUrl: process.env.FGA_API_URL, // required @@ -124,7 +124,7 @@ const fgaClient = new OpenFgaClient({ #### Client Credentials ```javascript -const { OpenFgaClient } = require('@openfga/sdk'); // OR import { OpenFgaClient } from '@openfga/sdk'; +const { OpenFgaClient, CredentialsMethod } = require('@openfga/sdk'); // OR import { OpenFgaClient, CredentialsMethod } from '@openfga/sdk'; const fgaClient = new OpenFgaClient({ apiUrl: process.env.FGA_API_URL, // required @@ -670,7 +670,7 @@ If a network request fails with a 429 or 5xx error from the server, the SDK will To customize this behavior, create an object with `maxRetry` and `minWaitInMs` properties. `maxRetry` determines the maximum number of retries (up to 15), while `minWaitInMs` sets the minimum wait time between retries in milliseconds. -Apply your custom retry values by setting to `retryParams` on the configuration object passed to the `OpenFgaClient` call. +Apply your custom retry values by setting to `retryParams` on the to the configuration object passed to the `OpenFgaClient` call. ```javascript const { OpenFgaClient } = require('@openfga/sdk'); // OR import { OpenFgaClient } from '@openfga/sdk'; diff --git a/api.ts b/api.ts index 2b3b0dc..3f650ca 100644 --- a/api.ts +++ b/api.ts @@ -761,7 +761,8 @@ export const OpenFgaApiFp = function(configuration: Configuration, credentials: return createRequestFunction(localVarAxiosArgs, globalAxios, configuration, credentials, { [TelemetryAttribute.FgaClientRequestMethod]: "Check", [TelemetryAttribute.FgaClientRequestStoreId]: storeId ?? "", - ...TelemetryAttributes.fromRequestBody(body) + [TelemetryAttribute.FgaClientRequestModelId]: body.authorization_model_id ?? "", + [TelemetryAttribute.FgaClientUser]: body.tuple_key.user }); }, /** @@ -775,7 +776,6 @@ export const OpenFgaApiFp = function(configuration: Configuration, credentials: const localVarAxiosArgs = localVarAxiosParamCreator.createStore(body, options); return createRequestFunction(localVarAxiosArgs, globalAxios, configuration, credentials, { [TelemetryAttribute.FgaClientRequestMethod]: "CreateStore", - ...TelemetryAttributes.fromRequestBody(body) }); }, /** @@ -789,7 +789,7 @@ export const OpenFgaApiFp = function(configuration: Configuration, credentials: const localVarAxiosArgs = localVarAxiosParamCreator.deleteStore(storeId, options); return createRequestFunction(localVarAxiosArgs, globalAxios, configuration, credentials, { [TelemetryAttribute.FgaClientRequestMethod]: "DeleteStore", - [TelemetryAttribute.FgaClientRequestStoreId]: storeId ?? "", + [TelemetryAttribute.FgaClientRequestStoreId]: storeId, }); }, /** @@ -804,8 +804,8 @@ export const OpenFgaApiFp = function(configuration: Configuration, credentials: const localVarAxiosArgs = localVarAxiosParamCreator.expand(storeId, body, options); return createRequestFunction(localVarAxiosArgs, globalAxios, configuration, credentials, { [TelemetryAttribute.FgaClientRequestMethod]: "Expand", + [TelemetryAttribute.FgaClientRequestModelId]: body.authorization_model_id ?? "", [TelemetryAttribute.FgaClientRequestStoreId]: storeId ?? "", - ...TelemetryAttributes.fromRequestBody(body) }); }, /** @@ -819,7 +819,7 @@ export const OpenFgaApiFp = function(configuration: Configuration, credentials: const localVarAxiosArgs = localVarAxiosParamCreator.getStore(storeId, options); return createRequestFunction(localVarAxiosArgs, globalAxios, configuration, credentials, { [TelemetryAttribute.FgaClientRequestMethod]: "GetStore", - [TelemetryAttribute.FgaClientRequestStoreId]: storeId ?? "", + [TelemetryAttribute.FgaClientRequestStoreId]: storeId, }); }, /** @@ -835,11 +835,12 @@ export const OpenFgaApiFp = function(configuration: Configuration, credentials: return createRequestFunction(localVarAxiosArgs, globalAxios, configuration, credentials, { [TelemetryAttribute.FgaClientRequestMethod]: "ListObjects", [TelemetryAttribute.FgaClientRequestStoreId]: storeId ?? "", - ...TelemetryAttributes.fromRequestBody(body) + [TelemetryAttribute.FgaClientRequestModelId]: body.authorization_model_id ?? "", + [TelemetryAttribute.FgaClientUser]: body.user }); }, /** - * Returns a paginated list of OpenFGA stores and a continuation token to get additional stores. The continuation token will be empty if there are no more stores. + * Returns a paginated list of OpenFGA stores and a continuation token to get additional stores. The continuation token will be empty if there are no more stores. * @summary List all stores * @param {number} [pageSize] * @param {string} [continuationToken] @@ -865,7 +866,7 @@ export const OpenFgaApiFp = function(configuration: Configuration, credentials: return createRequestFunction(localVarAxiosArgs, globalAxios, configuration, credentials, { [TelemetryAttribute.FgaClientRequestMethod]: "ListUsers", [TelemetryAttribute.FgaClientRequestStoreId]: storeId ?? "", - ...TelemetryAttributes.fromRequestBody(body) + [TelemetryAttribute.FgaClientRequestModelId]: body.authorization_model_id ?? "", }); }, /** @@ -880,12 +881,11 @@ export const OpenFgaApiFp = function(configuration: Configuration, credentials: const localVarAxiosArgs = localVarAxiosParamCreator.read(storeId, body, options); return createRequestFunction(localVarAxiosArgs, globalAxios, configuration, credentials, { [TelemetryAttribute.FgaClientRequestMethod]: "Read", - [TelemetryAttribute.FgaClientRequestStoreId]: storeId ?? "", - ...TelemetryAttributes.fromRequestBody(body) + [TelemetryAttribute.FgaClientRequestStoreId]: storeId, }); }, /** - * The ReadAssertions API will return, for a given authorization model id, all the assertions stored for it. An assertion is an object that contains a tuple key, and the expectation of whether a call to the Check API of that tuple key will return true or false. + * The ReadAssertions API will return, for a given authorization model id, all the assertions stored for it. An assertion is an object that contains a tuple key, and the expectation of whether a call to the Check API of that tuple key will return true or false. * @summary Read assertions for an authorization model ID * @param {string} storeId * @param {string} authorizationModelId @@ -896,7 +896,8 @@ export const OpenFgaApiFp = function(configuration: Configuration, credentials: const localVarAxiosArgs = localVarAxiosParamCreator.readAssertions(storeId, authorizationModelId, options); return createRequestFunction(localVarAxiosArgs, globalAxios, configuration, credentials, { [TelemetryAttribute.FgaClientRequestMethod]: "ReadAssertions", - [TelemetryAttribute.FgaClientRequestStoreId]: storeId ?? "", + [TelemetryAttribute.FgaClientRequestStoreId]: storeId, + [TelemetryAttribute.FgaClientRequestModelId]: authorizationModelId, }); }, /** @@ -911,7 +912,7 @@ export const OpenFgaApiFp = function(configuration: Configuration, credentials: const localVarAxiosArgs = localVarAxiosParamCreator.readAuthorizationModel(storeId, id, options); return createRequestFunction(localVarAxiosArgs, globalAxios, configuration, credentials, { [TelemetryAttribute.FgaClientRequestMethod]: "ReadAuthorizationModel", - [TelemetryAttribute.FgaClientRequestStoreId]: storeId ?? "", + [TelemetryAttribute.FgaClientRequestStoreId]: storeId, }); }, /** @@ -927,7 +928,7 @@ export const OpenFgaApiFp = function(configuration: Configuration, credentials: const localVarAxiosArgs = localVarAxiosParamCreator.readAuthorizationModels(storeId, pageSize, continuationToken, options); return createRequestFunction(localVarAxiosArgs, globalAxios, configuration, credentials, { [TelemetryAttribute.FgaClientRequestMethod]: "ReadAuthorizationModels", - [TelemetryAttribute.FgaClientRequestStoreId]: storeId ?? "", + [TelemetryAttribute.FgaClientRequestStoreId]: storeId, }); }, /** @@ -944,7 +945,7 @@ export const OpenFgaApiFp = function(configuration: Configuration, credentials: const localVarAxiosArgs = localVarAxiosParamCreator.readChanges(storeId, type, pageSize, continuationToken, options); return createRequestFunction(localVarAxiosArgs, globalAxios, configuration, credentials, { [TelemetryAttribute.FgaClientRequestMethod]: "ReadChanges", - [TelemetryAttribute.FgaClientRequestStoreId]: storeId ?? "", + [TelemetryAttribute.FgaClientRequestStoreId]: storeId, }); }, /** @@ -960,7 +961,7 @@ export const OpenFgaApiFp = function(configuration: Configuration, credentials: return createRequestFunction(localVarAxiosArgs, globalAxios, configuration, credentials, { [TelemetryAttribute.FgaClientRequestMethod]: "Write", [TelemetryAttribute.FgaClientRequestStoreId]: storeId ?? "", - ...TelemetryAttributes.fromRequestBody(body) + [TelemetryAttribute.FgaClientRequestModelId]: body.authorization_model_id ?? "", }); }, /** @@ -976,8 +977,8 @@ export const OpenFgaApiFp = function(configuration: Configuration, credentials: const localVarAxiosArgs = localVarAxiosParamCreator.writeAssertions(storeId, authorizationModelId, body, options); return createRequestFunction(localVarAxiosArgs, globalAxios, configuration, credentials, { [TelemetryAttribute.FgaClientRequestMethod]: "WriteAssertions", - [TelemetryAttribute.FgaClientRequestStoreId]: storeId ?? "", - ...TelemetryAttributes.fromRequestBody(body) + [TelemetryAttribute.FgaClientRequestStoreId]: storeId, + [TelemetryAttribute.FgaClientRequestModelId]: authorizationModelId, }); }, /** @@ -992,8 +993,7 @@ export const OpenFgaApiFp = function(configuration: Configuration, credentials: const localVarAxiosArgs = localVarAxiosParamCreator.writeAuthorizationModel(storeId, body, options); return createRequestFunction(localVarAxiosArgs, globalAxios, configuration, credentials, { [TelemetryAttribute.FgaClientRequestMethod]: "WriteAuthorizationModel", - [TelemetryAttribute.FgaClientRequestStoreId]: storeId ?? "", - ...TelemetryAttributes.fromRequestBody(body) + [TelemetryAttribute.FgaClientRequestStoreId]: storeId, }); }, }; diff --git a/client.ts b/client.ts index 481a4a0..0e00738 100644 --- a/client.ts +++ b/client.ts @@ -211,6 +211,8 @@ export class OpenFgaClient extends BaseAPI { this.configuration = new ClientConfiguration(configuration); } this.configuration.isValid(); + + this.api = new OpenFgaApi(this.configuration, axios); this.storeId = configuration.storeId; this.authorizationModelId = configuration.authorizationModelId; diff --git a/configuration.ts b/configuration.ts index fefb380..36fb0ce 100644 --- a/configuration.ts +++ b/configuration.ts @@ -186,9 +186,10 @@ export class Configuration { * @throws {FgaValidationError} */ public isValid(): boolean { - if (!this.apiUrl && !this.apiHost) { - assertParamExists("Configuration", "apiUrl", this.apiUrl); - } + if (!this.apiUrl) { + assertParamExists("Configuration", "apiScheme", this.apiScheme); + assertParamExists("Configuration", "apiHost", this.apiHost); + } if (!isWellFormedUriString(this.getBasePath())) { throw new FgaValidationError( diff --git a/docs/opentelemetry.md b/docs/opentelemetry.md index 5f7460d..c259fcf 100644 --- a/docs/opentelemetry.md +++ b/docs/opentelemetry.md @@ -1,8 +1,8 @@ # OpenTelemetry -This SDK produces [metrics](https://opentelemetry.io/docs/concepts/signals/metrics/) using [OpenTelemetry](https://opentelemetry.io/) to allow you to view data such as request timings. These metrics also include attributes for the model and store ID and the API called to allow you to build reporting. +This SDK produces [metrics](https://opentelemetry.io/docs/concepts/signals/metrics/) using [OpenTelemetry](https://opentelemetry.io/) that allow you to view data such as request timings. These metrics also include attributes for the model and store ID, as well as the API called to allow you to build reporting. -When an OpenTelemetry SDK instance is configured, the metrics will be exported and sent to the collector configured as part of your application's configuration. If you are not using OpenTelemetry, the metric functionality is a no-op and the events are never sent. +When an OpenTelemetry SDK instance is configured, the metrics will be exported and sent to the collector configured as part of your applications configuration. If you are not using OpenTelemetry, the metric functionality is a no-op and the events are never sent. In cases when metrics events are sent, they will not be viewable outside of infrastructure configured in your application, and are never available to the OpenFGA team or contributors. @@ -40,7 +40,7 @@ In cases when metrics events are sent, they will not be viewable outside of infr Not all attributes are enabled by default. -Some attributes, like `fga-client.user` have been disabled by default due to their high cardinality, which may result in very high costs when using some SaaS metric collectors. If you expect high cardinality for a specific attribute, you can disable it by updating the telemetry configuration accordingly. +Some attributes, like `fga-client.user` have been disabled by default due to their high cardinality, which may result for very high costs when using some SaaS metric collectors. If you expect to have a high cardinality for a specific attribute, you can disable it by updating the telemetry configuration accordingly. If your configuration does not specify a given metric, the default attributes for that metric will be used. @@ -97,4 +97,4 @@ const fgaClient = new OpenFgaClient({ ## Example -There is an [example project](https://github.com/openfga/js-sdk/blob/main/example/opentelemetry) that provides some guidance on how to configure OpenTelemetry available in the examples directory. +There is an [example project](https://github.com/openfga/js-sdk/blob/main/example/opentelemetry) that provides some guidance on how to configure OpenTelemetry available in the examples directory. \ No newline at end of file diff --git a/example/README.md b/example/README.md index 281ed3d..35456e1 100644 --- a/example/README.md +++ b/example/README.md @@ -4,7 +4,7 @@ A set of Examples on how to call the OpenFGA JS SDK ### Examples Example 1: -A bare-bones example. It creates a store and runs a set of calls against it including creating a model, writing tuples, and checking for access. +A bare-bones example. It creates a store, and runs a set of calls against it including creating a model, writing tuples and checking for access. OpenTelemetry: An example that demonstrates how to integrate the OpenFGA JS SDK with OpenTelemetry. @@ -42,4 +42,4 @@ to a `file:` reference like below ``` 3. If you have an OpenFGA server running, you can use it, otherwise run `make run-openfga` to spin up an instance (you'll need to switch to a different terminal after - don't forget to close it when done) 4. Run `make setup` to install dependencies -5. Run `make run` to run the example +5. Run `make run` to run the example \ No newline at end of file diff --git a/telemetry/attributes.ts b/telemetry/attributes.ts index 41ac4cd..93b9c89 100644 --- a/telemetry/attributes.ts +++ b/telemetry/attributes.ts @@ -111,16 +111,4 @@ export class TelemetryAttributes { return attributes; } - - static fromRequestBody(body: any, attributes: Record = {}): Record { - if (body?.authorization_model_id) { - attributes[TelemetryAttribute.FgaClientRequestModelId] = body.authorization_model_id; - } - - if (body?.tuple_key?.user) { - attributes[TelemetryAttribute.FgaClientUser] = body.tuple_key.user; - } - - return attributes; - } } diff --git a/tests/telemetry/attributes.test.ts b/tests/telemetry/attributes.test.ts index 33bfee5..e1551bc 100644 --- a/tests/telemetry/attributes.test.ts +++ b/tests/telemetry/attributes.test.ts @@ -90,20 +90,4 @@ describe("TelemetryAttributes", () => { expect(result["fga-client.response.model_id"]).toEqual("model-id"); expect(result["http.server.request.duration"]).toEqual(10); }); - - test("should create attributes from a request body correctly", () => { - const body = { authorization_model_id: "model-id", tuple_key: { user: "user:anne" } }; - const attributes = TelemetryAttributes.fromRequestBody(body); - - expect(attributes[TelemetryAttribute.FgaClientRequestModelId]).toEqual("model-id"); - expect(attributes[TelemetryAttribute.FgaClientUser]).toEqual("user:anne"); - }); - - test("should create attributes from a request body without tuple_key", () => { - const body = { authorization_model_id: "model-id" }; - const attributes = TelemetryAttributes.fromRequestBody(body); - - expect(attributes[TelemetryAttribute.FgaClientRequestModelId]).toEqual("model-id"); - expect(attributes[TelemetryAttribute.FgaClientUser]).toBeUndefined(); - }); }); From 1542c54de2ddbc8fd6736956274bd8cb64dc3baf Mon Sep 17 00:00:00 2001 From: Syed Waheed <105697767+Waheedsys@users.noreply.github.com> Date: Fri, 15 Nov 2024 11:02:46 -0600 Subject: [PATCH 2/5] fix: error correctly if apiUrl is not provided --- README.md | 4 ++-- client.ts | 2 -- configuration.ts | 5 ++--- docs/opentelemetry.md | 8 ++++---- example/README.md | 4 ++-- 5 files changed, 10 insertions(+), 13 deletions(-) diff --git a/README.md b/README.md index 211d4a3..8622845 100644 --- a/README.md +++ b/README.md @@ -87,7 +87,7 @@ yarn add @openfga/sdk [Learn how to initialize your SDK](https://openfga.dev/docs/getting-started/setup-sdk-client) -We strongly recommend you initialize the `OpenFgaClient` only once and then re-use it throughout your app, otherwise you will incur the cost of having to re-initialize multiple times or at every request, the cost of reduced connection pooling and re-use, and would be particularly costly in the client credentials flow, as that flow will be preformed on every request. +We strongly recommend you initialize the `OpenFgaClient` only once and then re-use it throughout your app, otherwise you will incur the cost of having to re-initialize multiple times or at every request, the cost of reduced connection pooling and re-use, and would be particularly costly in the client credentials flow, as that flow will be performed on every request. > The `OpenFgaClient` will by default retry API requests up to 15 times on 429 and 5xx errors. @@ -670,7 +670,7 @@ If a network request fails with a 429 or 5xx error from the server, the SDK will To customize this behavior, create an object with `maxRetry` and `minWaitInMs` properties. `maxRetry` determines the maximum number of retries (up to 15), while `minWaitInMs` sets the minimum wait time between retries in milliseconds. -Apply your custom retry values by setting to `retryParams` on the to the configuration object passed to the `OpenFgaClient` call. +Apply your custom retry values by setting to `retryParams` on the configuration object passed to the `OpenFgaClient` call. ```javascript const { OpenFgaClient } = require('@openfga/sdk'); // OR import { OpenFgaClient } from '@openfga/sdk'; diff --git a/client.ts b/client.ts index 0e00738..481a4a0 100644 --- a/client.ts +++ b/client.ts @@ -211,8 +211,6 @@ export class OpenFgaClient extends BaseAPI { this.configuration = new ClientConfiguration(configuration); } this.configuration.isValid(); - - this.api = new OpenFgaApi(this.configuration, axios); this.storeId = configuration.storeId; this.authorizationModelId = configuration.authorizationModelId; diff --git a/configuration.ts b/configuration.ts index 36fb0ce..ed0ba48 100644 --- a/configuration.ts +++ b/configuration.ts @@ -186,9 +186,8 @@ export class Configuration { * @throws {FgaValidationError} */ public isValid(): boolean { - if (!this.apiUrl) { - assertParamExists("Configuration", "apiScheme", this.apiScheme); - assertParamExists("Configuration", "apiHost", this.apiHost); + if (!this.apiUrl && !this.apiHost) { + assertParamExists("Configuration", "apiUrl", this.apiUrl); } if (!isWellFormedUriString(this.getBasePath())) { diff --git a/docs/opentelemetry.md b/docs/opentelemetry.md index c259fcf..5f7460d 100644 --- a/docs/opentelemetry.md +++ b/docs/opentelemetry.md @@ -1,8 +1,8 @@ # OpenTelemetry -This SDK produces [metrics](https://opentelemetry.io/docs/concepts/signals/metrics/) using [OpenTelemetry](https://opentelemetry.io/) that allow you to view data such as request timings. These metrics also include attributes for the model and store ID, as well as the API called to allow you to build reporting. +This SDK produces [metrics](https://opentelemetry.io/docs/concepts/signals/metrics/) using [OpenTelemetry](https://opentelemetry.io/) to allow you to view data such as request timings. These metrics also include attributes for the model and store ID and the API called to allow you to build reporting. -When an OpenTelemetry SDK instance is configured, the metrics will be exported and sent to the collector configured as part of your applications configuration. If you are not using OpenTelemetry, the metric functionality is a no-op and the events are never sent. +When an OpenTelemetry SDK instance is configured, the metrics will be exported and sent to the collector configured as part of your application's configuration. If you are not using OpenTelemetry, the metric functionality is a no-op and the events are never sent. In cases when metrics events are sent, they will not be viewable outside of infrastructure configured in your application, and are never available to the OpenFGA team or contributors. @@ -40,7 +40,7 @@ In cases when metrics events are sent, they will not be viewable outside of infr Not all attributes are enabled by default. -Some attributes, like `fga-client.user` have been disabled by default due to their high cardinality, which may result for very high costs when using some SaaS metric collectors. If you expect to have a high cardinality for a specific attribute, you can disable it by updating the telemetry configuration accordingly. +Some attributes, like `fga-client.user` have been disabled by default due to their high cardinality, which may result in very high costs when using some SaaS metric collectors. If you expect high cardinality for a specific attribute, you can disable it by updating the telemetry configuration accordingly. If your configuration does not specify a given metric, the default attributes for that metric will be used. @@ -97,4 +97,4 @@ const fgaClient = new OpenFgaClient({ ## Example -There is an [example project](https://github.com/openfga/js-sdk/blob/main/example/opentelemetry) that provides some guidance on how to configure OpenTelemetry available in the examples directory. \ No newline at end of file +There is an [example project](https://github.com/openfga/js-sdk/blob/main/example/opentelemetry) that provides some guidance on how to configure OpenTelemetry available in the examples directory. diff --git a/example/README.md b/example/README.md index 35456e1..281ed3d 100644 --- a/example/README.md +++ b/example/README.md @@ -4,7 +4,7 @@ A set of Examples on how to call the OpenFGA JS SDK ### Examples Example 1: -A bare-bones example. It creates a store, and runs a set of calls against it including creating a model, writing tuples and checking for access. +A bare-bones example. It creates a store and runs a set of calls against it including creating a model, writing tuples, and checking for access. OpenTelemetry: An example that demonstrates how to integrate the OpenFGA JS SDK with OpenTelemetry. @@ -42,4 +42,4 @@ to a `file:` reference like below ``` 3. If you have an OpenFGA server running, you can use it, otherwise run `make run-openfga` to spin up an instance (you'll need to switch to a different terminal after - don't forget to close it when done) 4. Run `make setup` to install dependencies -5. Run `make run` to run the example \ No newline at end of file +5. Run `make run` to run the example From 81524465728cb28ca8f3d837b932725292ac7d31 Mon Sep 17 00:00:00 2001 From: sccalabr <4111230+sccalabr@users.noreply.github.com> Date: Fri, 15 Nov 2024 11:05:31 -0600 Subject: [PATCH 3/5] [PATCH] docs:replace readable names with uuid --- CHANGELOG.md | 2 +- README.md | 58 +++++++++++++++++------------------ example/example1/example1.mjs | 8 ++--- tests/client.test.ts | 8 ++--- tests/helpers/nocks.ts | 2 +- tests/index.test.ts | 4 +-- 6 files changed, 41 insertions(+), 41 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 42776e4..6d6ac91 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -189,7 +189,7 @@ Updated to include support for [OpenFGA 0.3.0](https://github.com/openfga/openfg Changes: - [BREAKING] feat(list-objects)!: response has been changed to include the object type - e.g. response that was `{"object_ids":["roadmap"]}`, will now be `{"objects":["document:roadmap"]}` + e.g. response that was `{"object_ids":["roadmap"]}`, will now be `{"objects":["document:0192ab2a-d83f-756d-9397-c5ed9f3cb69a"]}` Fixes: - fix(models): update interfaces that had incorrectly optional fields to make them required diff --git a/README.md b/README.md index 8622845..1ef3d37 100644 --- a/README.md +++ b/README.md @@ -330,13 +330,13 @@ Reads the relationship tuples stored in the database. It does not evaluate nor e const body = { user: "user:81684243-9356-4421-8fbf-a4f8d36aa31b", relation: "viewer", - object: "document:roadmap", + object: "document:0192ab2a-d83f-756d-9397-c5ed9f3cb69a", }; // Find all relationship tuples where a certain user has any relation to a certain document const body = { user: "user:81684243-9356-4421-8fbf-a4f8d36aa31b", - object: "document:roadmap", + object: "document:0192ab2a-d83f-756d-9397-c5ed9f3cb69a", }; // Find all relationship tuples where a certain user is a viewer of any document @@ -354,7 +354,7 @@ const body = { // Find all relationship tuples where any user has any relation with a particular document const body = { - object: "document:roadmap", + object: "document:0192ab2a-d83f-756d-9397-c5ed9f3cb69a", }; // Read all stored relationship tuples @@ -383,13 +383,13 @@ const options = {}; options.authorizationModelId = "01GXSA8YR785C4FYS3C0RTG7B1"; await fgaClient.write({ - writes: [{ user: "user:81684243-9356-4421-8fbf-a4f8d36aa31b", relation: "viewer", object: "document:roadmap" }], - deletes: [{ user: "user:81684243-9356-4421-8fbf-a4f8d36aa31b", relation: "editor", object: "document:roadmap" }], + writes: [{ user: "user:81684243-9356-4421-8fbf-a4f8d36aa31b", relation: "viewer", object: "document:0192ab2a-d83f-756d-9397-c5ed9f3cb69a" }], + deletes: [{ user: "user:81684243-9356-4421-8fbf-a4f8d36aa31b", relation: "editor", object: "document:0192ab2a-d83f-756d-9397-c5ed9f3cb69a" }], }, options); // Convenience functions are available -await fgaClient.writeTuples([{ user: "user:81684243-9356-4421-8fbf-a4f8d36aa31b", relation: "viewer", object: "document:roadmap" }], options); -await fgaClient.deleteTuples([{ user: "user:81684243-9356-4421-8fbf-a4f8d36aa31b", relation: "editor", object: "document:roadmap" }], options); +await fgaClient.writeTuples([{ user: "user:81684243-9356-4421-8fbf-a4f8d36aa31b", relation: "viewer", object: "document:0192ab2a-d83f-756d-9397-c5ed9f3cb69a" }], options); +await fgaClient.deleteTuples([{ user: "user:81684243-9356-4421-8fbf-a4f8d36aa31b", relation: "editor", object: "document:0192ab2a-d83f-756d-9397-c5ed9f3cb69a" }], options); // if any error is encountered in the transaction mode, an error will be thrown ``` @@ -407,14 +407,14 @@ options.transaction = { }; const response = await fgaClient.write({ - writes: [{ user: "user:81684243-9356-4421-8fbf-a4f8d36aa31b", relation: "viewer", object: "document:roadmap" }], - deletes: [{ user: "user:81684243-9356-4421-8fbf-a4f8d36aa31b", relation: "editor", object: "document:roadmap" }], + writes: [{ user: "user:81684243-9356-4421-8fbf-a4f8d36aa31b", relation: "viewer", object: "document:0192ab2a-d83f-756d-9397-c5ed9f3cb69a" }], + deletes: [{ user: "user:81684243-9356-4421-8fbf-a4f8d36aa31b", relation: "editor", object: "document:0192ab2a-d83f-756d-9397-c5ed9f3cb69a" }], }, options); /* response = { - writes: [{ tuple_key: { user: "user:81684243-9356-4421-8fbf-a4f8d36aa31b", relation: "viewer", object: "document:roadmap", status: "success" } }], - deletes: [{ tuple_key: { user: "user:81684243-9356-4421-8fbf-a4f8d36aa31b", relation: "editor", object: "document:roadmap", status: "failure", err: } }], + writes: [{ tuple_key: { user: "user:81684243-9356-4421-8fbf-a4f8d36aa31b", relation: "viewer", object: "document:0192ab2a-d83f-756d-9397-c5ed9f3cb69a", status: "success" } }], + deletes: [{ tuple_key: { user: "user:81684243-9356-4421-8fbf-a4f8d36aa31b", relation: "editor", object: "document:0192ab2a-d83f-756d-9397-c5ed9f3cb69a", status: "failure", err: } }], }; */ ``` @@ -436,7 +436,7 @@ const options = { const result = await fgaClient.check({ user: "user:81684243-9356-4421-8fbf-a4f8d36aa31b", relation: "viewer", - object: "document:roadmap", + object: "document:0192ab2a-d83f-756d-9397-c5ed9f3cb69a", }, options); // result = { allowed: true } @@ -455,19 +455,19 @@ const options = { const { responses } = await fgaClient.batchCheck([{ user: "user:81684243-9356-4421-8fbf-a4f8d36aa31b", relation: "viewer", - object: "document:budget", + object: "document:0192ab2d-d36e-7cb3-a4a8-5d1d67a300c5", }, { user: "user:81684243-9356-4421-8fbf-a4f8d36aa31b", relation: "member", - object: "document:budget", + object: "document:0192ab2d-d36e-7cb3-a4a8-5d1d67a300c5", }, { user: "user:81684243-9356-4421-8fbf-a4f8d36aa31b", relation: "viewer", - object: "document:roadmap", + object: "document:0192ab2a-d83f-756d-9397-c5ed9f3cb69a", contextualTuples: [{ user: "user:81684243-9356-4421-8fbf-a4f8d36aa31b", relation: "writer", - object: "document:roadmap" + object: "document:0192ab2a-d83f-756d-9397-c5ed9f3cb69a" }], }], options); @@ -477,14 +477,14 @@ responses = [{ _request: { user: "user:81684243-9356-4421-8fbf-a4f8d36aa31b", relation: "viewer", - object: "document:budget", + object: "document:0192ab2d-d36e-7cb3-a4a8-5d1d67a300c5", } }, { allowed: false, _request: { user: "user:81684243-9356-4421-8fbf-a4f8d36aa31b", relation: "member", - object: "document:budget", + object: "document:0192ab2d-d36e-7cb3-a4a8-5d1d67a300c5", }, err: }, { @@ -492,11 +492,11 @@ responses = [{ _request: { user: "user:81684243-9356-4421-8fbf-a4f8d36aa31b", relation: "viewer", - object: "document:roadmap", + object: "document:0192ab2a-d83f-756d-9397-c5ed9f3cb69a", contextualTuples: [{ user: "user:81684243-9356-4421-8fbf-a4f8d36aa31b", relation: "writer", - object: "document:roadmap" + object: "document:0192ab2a-d83f-756d-9397-c5ed9f3cb69a" }], }}, ] @@ -517,10 +517,10 @@ options.authorizationModelId = "01GXSA8YR785C4FYS3C0RTG7B1"; const { tree } = await fgaClient.expand({ relation: "viewer", - object: "document:roadmap", + object: "document:0192ab2a-d83f-756d-9397-c5ed9f3cb69a", }, options); -// tree = { root: { name: "document:roadmap#viewer", leaf: { users: { users: ["user:81684243-9356-4421-8fbf-a4f8d36aa31b", "user:f52a4f7a-054d-47ff-bb6e-3ac81269988f"] } } } } +// tree = { root: { name: "document:0192ab2a-d83f-756d-9397-c5ed9f3cb69a#viewer", leaf: { users: { users: ["user:81684243-9356-4421-8fbf-a4f8d36aa31b", "user:f52a4f7a-054d-47ff-bb6e-3ac81269988f"] } } } } ``` ##### List Objects @@ -542,11 +542,11 @@ const response = await fgaClient.listObjects({ contextualTuples: [{ user: "user:81684243-9356-4421-8fbf-a4f8d36aa31b", relation: "writer", - object: "document:budget" + object: "document:0192ab2d-d36e-7cb3-a4a8-5d1d67a300c5" }], }, options); -// response.objects = ["document:roadmap"] +// response.objects = ["document:0192ab2a-d83f-756d-9397-c5ed9f3cb69a"] ``` ##### List Relations @@ -563,12 +563,12 @@ options.authorization_model_id = "1uHxCSuTP0VKPYSnkq1pbb1jeZw"; const response = await fgaClient.listRelations({ user: "user:81684243-9356-4421-8fbf-a4f8d36aa31b", - object: "document:roadmap", + object: "document:0192ab2a-d83f-756d-9397-c5ed9f3cb69a", relations: ["can_view", "can_edit", "can_delete"], contextualTuples: [{ user: "user:81684243-9356-4421-8fbf-a4f8d36aa31b", relation: "writer", - object: "document:roadmap" + object: "document:0192ab2a-d83f-756d-9397-c5ed9f3cb69a" }], }, options); @@ -610,7 +610,7 @@ const response = await fgaClient.listUsers({ }, { user: "folder:product", relation: "parent", - object: "document:roadmap" + object: "document:0192ab2a-d83f-756d-9397-c5ed9f3cb69a" }] }, options); @@ -637,7 +637,7 @@ const response = await fgaClient.readAssertions(options); response.assertions = [{ user: "user:81684243-9356-4421-8fbf-a4f8d36aa31b", relation: "viewer", - object: "document:roadmap", + object: "document:0192ab2a-d83f-756d-9397-c5ed9f3cb69a", expectation: true, }]; */ @@ -658,7 +658,7 @@ options.authorizationModelId = "01GXSA8YR785C4FYS3C0RTG7B1"; const response = await fgaClient.writeAssertions([{ user: "user:81684243-9356-4421-8fbf-a4f8d36aa31b", relation: "viewer", - object: "document:roadmap", + object: "document:0192ab2a-d83f-756d-9397-c5ed9f3cb69a", expectation: true, }], options); ``` diff --git a/example/example1/example1.mjs b/example/example1/example1.mjs index 52b4898..f8b82be 100644 --- a/example/example1/example1.mjs +++ b/example/example1/example1.mjs @@ -129,7 +129,7 @@ async function main () { { user: "user:anne", relation: "writer", - object: "document:roadmap", + object: "document:0192ab2a-d83f-756d-9397-c5ed9f3cb69a", condition: { name: "ViewCountLessThan200", context: { @@ -158,7 +158,7 @@ async function main () { const { allowed } = await fgaClient.check({ user: "user:anne", relation: "viewer", - object: "document:roadmap" + object: "document:0192ab2a-d83f-756d-9397-c5ed9f3cb69a" }); console.log(`Allowed: ${allowed}`); } catch (error) { @@ -173,7 +173,7 @@ async function main () { const { allowed } = await fgaClient.check({ user: "user:anne", relation: "viewer", - object: "document:roadmap", + object: "document:0192ab2a-d83f-756d-9397-c5ed9f3cb69a", context: { ViewCount: 100 } @@ -191,7 +191,7 @@ async function main () { { user: "user:carl", relation: "writer", - object: "document:roadmap", + object: "document:0192ab2a-d83f-756d-9397-c5ed9f3cb69a", expectation: false } ]); diff --git a/tests/client.test.ts b/tests/client.test.ts index 6c9470c..132177e 100644 --- a/tests/client.test.ts +++ b/tests/client.test.ts @@ -575,7 +575,7 @@ describe("OpenFGA Client", () => { describe("ListObjects", () => { it("should call the api and return the response", async () => { - const mockedResponse = { objects: ["document:roadmap"] }; + const mockedResponse = { objects: ["document:0192ab2a-d83f-756d-9397-c5ed9f3cb69a"] }; const scope = nocks.listObjects(baseConfig.storeId!, mockedResponse, undefined, ConsistencyPreference.HigherConsistency); expect(scope.isDone()).toBe(false); @@ -591,7 +591,7 @@ describe("OpenFGA Client", () => { }, { user: "folder:product", relation: "parent", - object: "document:roadmap" + object: "document:0192ab2a-d83f-756d-9397-c5ed9f3cb69a" }] }, { authorizationModelId: "01GAHCE4YVKPQEKZQHT2R89MQV", @@ -808,7 +808,7 @@ describe("OpenFGA Client", () => { }, { user: "folder:product", relation: "parent", - object: "document:roadmap" + object: "document:0192ab2a-d83f-756d-9397-c5ed9f3cb69a" }] }, { authorizationModelId: "01GAHCE4YVKPQEKZQHT2R89MQV", @@ -865,7 +865,7 @@ describe("OpenFGA Client", () => { await fgaClient.writeAssertions([{ user: "user:81684243-9356-4421-8fbf-a4f8d36aa31b", relation: "viewer", - object: "document:roadmap", + object: "document:0192ab2a-d83f-756d-9397-c5ed9f3cb69a", expectation: true, }], { authorizationModelId: modelId }); diff --git a/tests/helpers/nocks.ts b/tests/helpers/nocks.ts index bdb78d8..b73e50f 100644 --- a/tests/helpers/nocks.ts +++ b/tests/helpers/nocks.ts @@ -156,7 +156,7 @@ export const getNocks = ((nock: typeof Nock) => ({ tuple_key: { user: "user:81684243-9356-4421-8fbf-a4f8d36aa31b", relation: "viewer", - object: "document:roadmap" + object: "document:0192ab2a-d83f-756d-9397-c5ed9f3cb69a" }, operation: TupleOperation.Write, timestamp: "2000-01-01T00:00:00Z" diff --git a/tests/index.test.ts b/tests/index.test.ts index 9867ab0..0ec4b22 100644 --- a/tests/index.test.ts +++ b/tests/index.test.ts @@ -825,7 +825,7 @@ describe("OpenFGA SDK", function () { describe("listObjects", () => { it("should call the api and return the response", async () => { - const mockedResponse = { objects: ["document:roadmap"] }; + const mockedResponse = { objects: ["document:0192ab2a-d83f-756d-9397-c5ed9f3cb69a"] }; const scope = nocks.listObjects(baseConfig.storeId!, mockedResponse); expect(scope.isDone()).toBe(false); @@ -845,7 +845,7 @@ describe("OpenFGA SDK", function () { }, { user: "folder:product", relation: "parent", - object: "document:roadmap" + object: "document:0192ab2a-d83f-756d-9397-c5ed9f3cb69a" }] } }); From 1296ee92038097318943327b15c25e32e1d478c1 Mon Sep 17 00:00:00 2001 From: Ryan Quinn Date: Fri, 15 Nov 2024 11:11:06 -0600 Subject: [PATCH 4/5] fix: update SDK contributing docs --- CONTRIBUTING.md | 2 +- README.md | 60 ++++++++++++++++++++++++------------------------- 2 files changed, 31 insertions(+), 31 deletions(-) diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index 82cac46..47cff81 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -33,7 +33,7 @@ That repo includes an issue template that will walk through all the places to ch ### Submitting Pull Requests -Considering that the SDKs are autogenerated, please make sure to submit your Pull Requests to the [sdk-generator](https://github.com/openfga/sdk-generator). We will not accept PRs to this repository because they will be overwritten on the next sdk generation. +While we accept Pull Requests on this repository, the SDKs are autogenerated so please consider additionally submitting your Pull Requests to the [sdk-generator](https://github.com/openfga/sdk-generator) and linking the two PRs together and to the corresponding issue. This will greatly assist the OpenFGA team in being able to give timely reviews as well as deploying fixes and updates to our other SDKs as well. ## Getting in touch diff --git a/README.md b/README.md index 1ef3d37..c610327 100644 --- a/README.md +++ b/README.md @@ -330,13 +330,13 @@ Reads the relationship tuples stored in the database. It does not evaluate nor e const body = { user: "user:81684243-9356-4421-8fbf-a4f8d36aa31b", relation: "viewer", - object: "document:0192ab2a-d83f-756d-9397-c5ed9f3cb69a", + object: "document:roadmap", }; // Find all relationship tuples where a certain user has any relation to a certain document const body = { user: "user:81684243-9356-4421-8fbf-a4f8d36aa31b", - object: "document:0192ab2a-d83f-756d-9397-c5ed9f3cb69a", + object: "document:roadmap", }; // Find all relationship tuples where a certain user is a viewer of any document @@ -354,7 +354,7 @@ const body = { // Find all relationship tuples where any user has any relation with a particular document const body = { - object: "document:0192ab2a-d83f-756d-9397-c5ed9f3cb69a", + object: "document:roadmap", }; // Read all stored relationship tuples @@ -383,13 +383,13 @@ const options = {}; options.authorizationModelId = "01GXSA8YR785C4FYS3C0RTG7B1"; await fgaClient.write({ - writes: [{ user: "user:81684243-9356-4421-8fbf-a4f8d36aa31b", relation: "viewer", object: "document:0192ab2a-d83f-756d-9397-c5ed9f3cb69a" }], - deletes: [{ user: "user:81684243-9356-4421-8fbf-a4f8d36aa31b", relation: "editor", object: "document:0192ab2a-d83f-756d-9397-c5ed9f3cb69a" }], + writes: [{ user: "user:81684243-9356-4421-8fbf-a4f8d36aa31b", relation: "viewer", object: "document:roadmap" }], + deletes: [{ user: "user:81684243-9356-4421-8fbf-a4f8d36aa31b", relation: "editor", object: "document:roadmap" }], }, options); // Convenience functions are available -await fgaClient.writeTuples([{ user: "user:81684243-9356-4421-8fbf-a4f8d36aa31b", relation: "viewer", object: "document:0192ab2a-d83f-756d-9397-c5ed9f3cb69a" }], options); -await fgaClient.deleteTuples([{ user: "user:81684243-9356-4421-8fbf-a4f8d36aa31b", relation: "editor", object: "document:0192ab2a-d83f-756d-9397-c5ed9f3cb69a" }], options); +await fgaClient.writeTuples([{ user: "user:81684243-9356-4421-8fbf-a4f8d36aa31b", relation: "viewer", object: "document:roadmap" }], options); +await fgaClient.deleteTuples([{ user: "user:81684243-9356-4421-8fbf-a4f8d36aa31b", relation: "editor", object: "document:roadmap" }], options); // if any error is encountered in the transaction mode, an error will be thrown ``` @@ -407,14 +407,14 @@ options.transaction = { }; const response = await fgaClient.write({ - writes: [{ user: "user:81684243-9356-4421-8fbf-a4f8d36aa31b", relation: "viewer", object: "document:0192ab2a-d83f-756d-9397-c5ed9f3cb69a" }], - deletes: [{ user: "user:81684243-9356-4421-8fbf-a4f8d36aa31b", relation: "editor", object: "document:0192ab2a-d83f-756d-9397-c5ed9f3cb69a" }], + writes: [{ user: "user:81684243-9356-4421-8fbf-a4f8d36aa31b", relation: "viewer", object: "document:roadmap" }], + deletes: [{ user: "user:81684243-9356-4421-8fbf-a4f8d36aa31b", relation: "editor", object: "document:roadmap" }], }, options); /* response = { - writes: [{ tuple_key: { user: "user:81684243-9356-4421-8fbf-a4f8d36aa31b", relation: "viewer", object: "document:0192ab2a-d83f-756d-9397-c5ed9f3cb69a", status: "success" } }], - deletes: [{ tuple_key: { user: "user:81684243-9356-4421-8fbf-a4f8d36aa31b", relation: "editor", object: "document:0192ab2a-d83f-756d-9397-c5ed9f3cb69a", status: "failure", err: } }], + writes: [{ tuple_key: { user: "user:81684243-9356-4421-8fbf-a4f8d36aa31b", relation: "viewer", object: "document:roadmap", status: "success" } }], + deletes: [{ tuple_key: { user: "user:81684243-9356-4421-8fbf-a4f8d36aa31b", relation: "editor", object: "document:roadmap", status: "failure", err: } }], }; */ ``` @@ -436,7 +436,7 @@ const options = { const result = await fgaClient.check({ user: "user:81684243-9356-4421-8fbf-a4f8d36aa31b", relation: "viewer", - object: "document:0192ab2a-d83f-756d-9397-c5ed9f3cb69a", + object: "document:roadmap", }, options); // result = { allowed: true } @@ -455,19 +455,19 @@ const options = { const { responses } = await fgaClient.batchCheck([{ user: "user:81684243-9356-4421-8fbf-a4f8d36aa31b", relation: "viewer", - object: "document:0192ab2d-d36e-7cb3-a4a8-5d1d67a300c5", + object: "document:budget", }, { user: "user:81684243-9356-4421-8fbf-a4f8d36aa31b", relation: "member", - object: "document:0192ab2d-d36e-7cb3-a4a8-5d1d67a300c5", + object: "document:budget", }, { user: "user:81684243-9356-4421-8fbf-a4f8d36aa31b", relation: "viewer", - object: "document:0192ab2a-d83f-756d-9397-c5ed9f3cb69a", + object: "document:roadmap", contextualTuples: [{ user: "user:81684243-9356-4421-8fbf-a4f8d36aa31b", relation: "writer", - object: "document:0192ab2a-d83f-756d-9397-c5ed9f3cb69a" + object: "document:roadmap" }], }], options); @@ -477,14 +477,14 @@ responses = [{ _request: { user: "user:81684243-9356-4421-8fbf-a4f8d36aa31b", relation: "viewer", - object: "document:0192ab2d-d36e-7cb3-a4a8-5d1d67a300c5", + object: "document:budget", } }, { allowed: false, _request: { user: "user:81684243-9356-4421-8fbf-a4f8d36aa31b", relation: "member", - object: "document:0192ab2d-d36e-7cb3-a4a8-5d1d67a300c5", + object: "document:budget", }, err: }, { @@ -492,11 +492,11 @@ responses = [{ _request: { user: "user:81684243-9356-4421-8fbf-a4f8d36aa31b", relation: "viewer", - object: "document:0192ab2a-d83f-756d-9397-c5ed9f3cb69a", + object: "document:roadmap", contextualTuples: [{ user: "user:81684243-9356-4421-8fbf-a4f8d36aa31b", relation: "writer", - object: "document:0192ab2a-d83f-756d-9397-c5ed9f3cb69a" + object: "document:roadmap" }], }}, ] @@ -517,10 +517,10 @@ options.authorizationModelId = "01GXSA8YR785C4FYS3C0RTG7B1"; const { tree } = await fgaClient.expand({ relation: "viewer", - object: "document:0192ab2a-d83f-756d-9397-c5ed9f3cb69a", + object: "document:roadmap", }, options); -// tree = { root: { name: "document:0192ab2a-d83f-756d-9397-c5ed9f3cb69a#viewer", leaf: { users: { users: ["user:81684243-9356-4421-8fbf-a4f8d36aa31b", "user:f52a4f7a-054d-47ff-bb6e-3ac81269988f"] } } } } +// tree = { root: { name: "document:roadmap#viewer", leaf: { users: { users: ["user:81684243-9356-4421-8fbf-a4f8d36aa31b", "user:f52a4f7a-054d-47ff-bb6e-3ac81269988f"] } } } } ``` ##### List Objects @@ -542,11 +542,11 @@ const response = await fgaClient.listObjects({ contextualTuples: [{ user: "user:81684243-9356-4421-8fbf-a4f8d36aa31b", relation: "writer", - object: "document:0192ab2d-d36e-7cb3-a4a8-5d1d67a300c5" + object: "document:budget" }], }, options); -// response.objects = ["document:0192ab2a-d83f-756d-9397-c5ed9f3cb69a"] +// response.objects = ["document:roadmap"] ``` ##### List Relations @@ -563,12 +563,12 @@ options.authorization_model_id = "1uHxCSuTP0VKPYSnkq1pbb1jeZw"; const response = await fgaClient.listRelations({ user: "user:81684243-9356-4421-8fbf-a4f8d36aa31b", - object: "document:0192ab2a-d83f-756d-9397-c5ed9f3cb69a", + object: "document:roadmap", relations: ["can_view", "can_edit", "can_delete"], contextualTuples: [{ user: "user:81684243-9356-4421-8fbf-a4f8d36aa31b", relation: "writer", - object: "document:0192ab2a-d83f-756d-9397-c5ed9f3cb69a" + object: "document:roadmap" }], }, options); @@ -610,7 +610,7 @@ const response = await fgaClient.listUsers({ }, { user: "folder:product", relation: "parent", - object: "document:0192ab2a-d83f-756d-9397-c5ed9f3cb69a" + object: "document:roadmap" }] }, options); @@ -637,7 +637,7 @@ const response = await fgaClient.readAssertions(options); response.assertions = [{ user: "user:81684243-9356-4421-8fbf-a4f8d36aa31b", relation: "viewer", - object: "document:0192ab2a-d83f-756d-9397-c5ed9f3cb69a", + object: "document:roadmap", expectation: true, }]; */ @@ -658,7 +658,7 @@ options.authorizationModelId = "01GXSA8YR785C4FYS3C0RTG7B1"; const response = await fgaClient.writeAssertions([{ user: "user:81684243-9356-4421-8fbf-a4f8d36aa31b", relation: "viewer", - object: "document:0192ab2a-d83f-756d-9397-c5ed9f3cb69a", + object: "document:roadmap", expectation: true, }], options); ``` @@ -724,7 +724,7 @@ If you have found a bug or if you have a feature request, please report them on ### Pull Requests -All changes made to this repo will be overwritten on the next generation, so we kindly ask that you send all pull requests related to the SDKs to the [sdk-generator repo](https://github.com/openfga/sdk-generator) instead. +While we accept Pull Requests on this repository, the SDKs are autogenerated so please consider additionally submitting your Pull Requests to the [sdk-generator](https://github.com/openfga/sdk-generator) and linking the two PRs together and to the corresponding issue. This will greatly assist the OpenFGA team in being able to give timely reviews as well as deploying fixes and updates to our other SDKs as well. ## Author From 6be30502c2c4df8c5c060129a6ddee63207d5e3f Mon Sep 17 00:00:00 2001 From: Ryan Quinn Date: Fri, 15 Nov 2024 11:19:52 -0600 Subject: [PATCH 5/5] Sync latest from sdk-generator --- README.md | 58 +++++++++++----------- api.ts | 80 +++++++++++++++--------------- apiModel.ts | 57 +++++++++++++++++++-- telemetry/attributes.ts | 12 +++++ tests/telemetry/attributes.test.ts | 16 ++++++ 5 files changed, 152 insertions(+), 71 deletions(-) diff --git a/README.md b/README.md index c610327..d725d7d 100644 --- a/README.md +++ b/README.md @@ -330,13 +330,13 @@ Reads the relationship tuples stored in the database. It does not evaluate nor e const body = { user: "user:81684243-9356-4421-8fbf-a4f8d36aa31b", relation: "viewer", - object: "document:roadmap", + object: "document:0192ab2a-d83f-756d-9397-c5ed9f3cb69a", }; // Find all relationship tuples where a certain user has any relation to a certain document const body = { user: "user:81684243-9356-4421-8fbf-a4f8d36aa31b", - object: "document:roadmap", + object: "document:0192ab2a-d83f-756d-9397-c5ed9f3cb69a", }; // Find all relationship tuples where a certain user is a viewer of any document @@ -354,7 +354,7 @@ const body = { // Find all relationship tuples where any user has any relation with a particular document const body = { - object: "document:roadmap", + object: "document:0192ab2a-d83f-756d-9397-c5ed9f3cb69a", }; // Read all stored relationship tuples @@ -383,13 +383,13 @@ const options = {}; options.authorizationModelId = "01GXSA8YR785C4FYS3C0RTG7B1"; await fgaClient.write({ - writes: [{ user: "user:81684243-9356-4421-8fbf-a4f8d36aa31b", relation: "viewer", object: "document:roadmap" }], - deletes: [{ user: "user:81684243-9356-4421-8fbf-a4f8d36aa31b", relation: "editor", object: "document:roadmap" }], + writes: [{ user: "user:81684243-9356-4421-8fbf-a4f8d36aa31b", relation: "viewer", object: "document:0192ab2a-d83f-756d-9397-c5ed9f3cb69a" }], + deletes: [{ user: "user:81684243-9356-4421-8fbf-a4f8d36aa31b", relation: "editor", object: "document:0192ab2a-d83f-756d-9397-c5ed9f3cb69a" }], }, options); // Convenience functions are available -await fgaClient.writeTuples([{ user: "user:81684243-9356-4421-8fbf-a4f8d36aa31b", relation: "viewer", object: "document:roadmap" }], options); -await fgaClient.deleteTuples([{ user: "user:81684243-9356-4421-8fbf-a4f8d36aa31b", relation: "editor", object: "document:roadmap" }], options); +await fgaClient.writeTuples([{ user: "user:81684243-9356-4421-8fbf-a4f8d36aa31b", relation: "viewer", object: "document:0192ab2a-d83f-756d-9397-c5ed9f3cb69a" }], options); +await fgaClient.deleteTuples([{ user: "user:81684243-9356-4421-8fbf-a4f8d36aa31b", relation: "editor", object: "document:0192ab2a-d83f-756d-9397-c5ed9f3cb69a" }], options); // if any error is encountered in the transaction mode, an error will be thrown ``` @@ -407,14 +407,14 @@ options.transaction = { }; const response = await fgaClient.write({ - writes: [{ user: "user:81684243-9356-4421-8fbf-a4f8d36aa31b", relation: "viewer", object: "document:roadmap" }], - deletes: [{ user: "user:81684243-9356-4421-8fbf-a4f8d36aa31b", relation: "editor", object: "document:roadmap" }], + writes: [{ user: "user:81684243-9356-4421-8fbf-a4f8d36aa31b", relation: "viewer", object: "document:0192ab2a-d83f-756d-9397-c5ed9f3cb69a" }], + deletes: [{ user: "user:81684243-9356-4421-8fbf-a4f8d36aa31b", relation: "editor", object: "document:0192ab2a-d83f-756d-9397-c5ed9f3cb69a" }], }, options); /* response = { - writes: [{ tuple_key: { user: "user:81684243-9356-4421-8fbf-a4f8d36aa31b", relation: "viewer", object: "document:roadmap", status: "success" } }], - deletes: [{ tuple_key: { user: "user:81684243-9356-4421-8fbf-a4f8d36aa31b", relation: "editor", object: "document:roadmap", status: "failure", err: } }], + writes: [{ tuple_key: { user: "user:81684243-9356-4421-8fbf-a4f8d36aa31b", relation: "viewer", object: "document:0192ab2a-d83f-756d-9397-c5ed9f3cb69a", status: "success" } }], + deletes: [{ tuple_key: { user: "user:81684243-9356-4421-8fbf-a4f8d36aa31b", relation: "editor", object: "document:0192ab2a-d83f-756d-9397-c5ed9f3cb69a", status: "failure", err: } }], }; */ ``` @@ -436,7 +436,7 @@ const options = { const result = await fgaClient.check({ user: "user:81684243-9356-4421-8fbf-a4f8d36aa31b", relation: "viewer", - object: "document:roadmap", + object: "document:0192ab2a-d83f-756d-9397-c5ed9f3cb69a", }, options); // result = { allowed: true } @@ -455,19 +455,19 @@ const options = { const { responses } = await fgaClient.batchCheck([{ user: "user:81684243-9356-4421-8fbf-a4f8d36aa31b", relation: "viewer", - object: "document:budget", + object: "document:0192ab2d-d36e-7cb3-a4a8-5d1d67a300c5", }, { user: "user:81684243-9356-4421-8fbf-a4f8d36aa31b", relation: "member", - object: "document:budget", + object: "document:0192ab2d-d36e-7cb3-a4a8-5d1d67a300c5", }, { user: "user:81684243-9356-4421-8fbf-a4f8d36aa31b", relation: "viewer", - object: "document:roadmap", + object: "document:0192ab2a-d83f-756d-9397-c5ed9f3cb69a", contextualTuples: [{ user: "user:81684243-9356-4421-8fbf-a4f8d36aa31b", relation: "writer", - object: "document:roadmap" + object: "document:0192ab2a-d83f-756d-9397-c5ed9f3cb69a" }], }], options); @@ -477,14 +477,14 @@ responses = [{ _request: { user: "user:81684243-9356-4421-8fbf-a4f8d36aa31b", relation: "viewer", - object: "document:budget", + object: "document:0192ab2d-d36e-7cb3-a4a8-5d1d67a300c5", } }, { allowed: false, _request: { user: "user:81684243-9356-4421-8fbf-a4f8d36aa31b", relation: "member", - object: "document:budget", + object: "document:0192ab2d-d36e-7cb3-a4a8-5d1d67a300c5", }, err: }, { @@ -492,11 +492,11 @@ responses = [{ _request: { user: "user:81684243-9356-4421-8fbf-a4f8d36aa31b", relation: "viewer", - object: "document:roadmap", + object: "document:0192ab2a-d83f-756d-9397-c5ed9f3cb69a", contextualTuples: [{ user: "user:81684243-9356-4421-8fbf-a4f8d36aa31b", relation: "writer", - object: "document:roadmap" + object: "document:0192ab2a-d83f-756d-9397-c5ed9f3cb69a" }], }}, ] @@ -517,10 +517,10 @@ options.authorizationModelId = "01GXSA8YR785C4FYS3C0RTG7B1"; const { tree } = await fgaClient.expand({ relation: "viewer", - object: "document:roadmap", + object: "document:0192ab2a-d83f-756d-9397-c5ed9f3cb69a", }, options); -// tree = { root: { name: "document:roadmap#viewer", leaf: { users: { users: ["user:81684243-9356-4421-8fbf-a4f8d36aa31b", "user:f52a4f7a-054d-47ff-bb6e-3ac81269988f"] } } } } +// tree = { root: { name: "document:0192ab2a-d83f-756d-9397-c5ed9f3cb69a#viewer", leaf: { users: { users: ["user:81684243-9356-4421-8fbf-a4f8d36aa31b", "user:f52a4f7a-054d-47ff-bb6e-3ac81269988f"] } } } } ``` ##### List Objects @@ -542,11 +542,11 @@ const response = await fgaClient.listObjects({ contextualTuples: [{ user: "user:81684243-9356-4421-8fbf-a4f8d36aa31b", relation: "writer", - object: "document:budget" + object: "document:0192ab2d-d36e-7cb3-a4a8-5d1d67a300c5" }], }, options); -// response.objects = ["document:roadmap"] +// response.objects = ["document:0192ab2a-d83f-756d-9397-c5ed9f3cb69a"] ``` ##### List Relations @@ -563,12 +563,12 @@ options.authorization_model_id = "1uHxCSuTP0VKPYSnkq1pbb1jeZw"; const response = await fgaClient.listRelations({ user: "user:81684243-9356-4421-8fbf-a4f8d36aa31b", - object: "document:roadmap", + object: "document:0192ab2a-d83f-756d-9397-c5ed9f3cb69a", relations: ["can_view", "can_edit", "can_delete"], contextualTuples: [{ user: "user:81684243-9356-4421-8fbf-a4f8d36aa31b", relation: "writer", - object: "document:roadmap" + object: "document:0192ab2a-d83f-756d-9397-c5ed9f3cb69a" }], }, options); @@ -610,7 +610,7 @@ const response = await fgaClient.listUsers({ }, { user: "folder:product", relation: "parent", - object: "document:roadmap" + object: "document:0192ab2a-d83f-756d-9397-c5ed9f3cb69a" }] }, options); @@ -637,7 +637,7 @@ const response = await fgaClient.readAssertions(options); response.assertions = [{ user: "user:81684243-9356-4421-8fbf-a4f8d36aa31b", relation: "viewer", - object: "document:roadmap", + object: "document:0192ab2a-d83f-756d-9397-c5ed9f3cb69a", expectation: true, }]; */ @@ -658,7 +658,7 @@ options.authorizationModelId = "01GXSA8YR785C4FYS3C0RTG7B1"; const response = await fgaClient.writeAssertions([{ user: "user:81684243-9356-4421-8fbf-a4f8d36aa31b", relation: "viewer", - object: "document:roadmap", + object: "document:0192ab2a-d83f-756d-9397-c5ed9f3cb69a", expectation: true, }], options); ``` diff --git a/api.ts b/api.ts index 3f650ca..586315b 100644 --- a/api.ts +++ b/api.ts @@ -33,6 +33,7 @@ import { Any, Assertion, AssertionTupleKey, + AuthErrorCode, AuthorizationModel, CheckRequest, CheckRequestTupleKey, @@ -51,6 +52,7 @@ import { ExpandRequestTupleKey, ExpandResponse, FgaObject, + ForbiddenResponse, GetStoreResponse, InternalErrorCode, InternalErrorMessageResponse, @@ -119,7 +121,7 @@ import { TelemetryAttribute, TelemetryAttributes } from "./telemetry/attributes" export const OpenFgaApiAxiosParamCreator = function (configuration: Configuration, credentials: Credentials) { return { /** - * The Check API returns whether a given user has a relationship with a given object in a given store. The `user` field of the request can be a specific target, such as `user:anne`, or a userset (set of users) such as `group:marketing#member` or a type-bound public access `user:*`. To arrive at a result, the API uses: an authorization model, explicit tuples written through the Write API, contextual tuples present in the request, and implicit tuples that exist by virtue of applying set theory (such as `document:2021-budget#viewer@document:2021-budget#viewer`; the set of users who are viewers of `document:2021-budget` are the set of users who are the viewers of `document:2021-budget`). A `contextual_tuples` object may also be included in the body of the request. This object contains one field `tuple_keys`, which is an array of tuple keys. Each of these tuples may have an associated `condition`. You may also provide an `authorization_model_id` in the body. This will be used to assert that the input `tuple_key` is valid for the model specified. If not specified, the assertion will be made against the latest authorization model ID. It is strongly recommended to specify authorization model id for better performance. You may also provide a `context` object that will be used to evaluate the conditioned tuples in the system. It is strongly recommended to provide a value for all the input parameters of all the conditions, to ensure that all tuples be evaluated correctly. The response will return whether the relationship exists in the field `allowed`. Some exceptions apply, but in general, if a Check API responds with `{allowed: true}`, then you can expect the equivalent ListObjects query to return the object, and viceversa. For example, if `Check(user:anne, reader, document:2021-budget)` responds with `{allowed: true}`, then `ListObjects(user:anne, reader, document)` may include `document:2021-budget` in the response. ## Examples ### Querying with contextual tuples In order to check if user `user:anne` of type `user` has a `reader` relationship with object `document:2021-budget` given the following contextual tuple ```json { \"user\": \"user:anne\", \"relation\": \"member\", \"object\": \"time_slot:office_hours\" } ``` the Check API can be used with the following request body: ```json { \"tuple_key\": { \"user\": \"user:anne\", \"relation\": \"reader\", \"object\": \"document:2021-budget\" }, \"contextual_tuples\": { \"tuple_keys\": [ { \"user\": \"user:anne\", \"relation\": \"member\", \"object\": \"time_slot:office_hours\" } ] }, \"authorization_model_id\": \"01G50QVV17PECNVAHX1GG4Y5NC\" } ``` ### Querying usersets Some Checks will always return `true`, even without any tuples. For example, for the following authorization model ```python model schema 1.1 type user type document relations define reader: [user] ``` the following query ```json { \"tuple_key\": { \"user\": \"document:2021-budget#reader\", \"relation\": \"reader\", \"object\": \"document:2021-budget\" } } ``` will always return `{ \"allowed\": true }`. This is because usersets are self-defining: the userset `document:2021-budget#reader` will always have the `reader` relation with `document:2021-budget`. ### Querying usersets with difference in the model A Check for a userset can yield results that must be treated carefully if the model involves difference. For example, for the following authorization model ```python model schema 1.1 type user type group relations define member: [user] type document relations define blocked: [user] define reader: [group#member] but not blocked ``` the following query ```json { \"tuple_key\": { \"user\": \"group:finance#member\", \"relation\": \"reader\", \"object\": \"document:2021-budget\" }, \"contextual_tuples\": { \"tuple_keys\": [ { \"user\": \"user:anne\", \"relation\": \"member\", \"object\": \"group:finance\" }, { \"user\": \"group:finance#member\", \"relation\": \"reader\", \"object\": \"document:2021-budget\" }, { \"user\": \"user:anne\", \"relation\": \"blocked\", \"object\": \"document:2021-budget\" } ] }, } ``` will return `{ \"allowed\": true }`, even though a specific user of the userset `group:finance#member` does not have the `reader` relationship with the given object. + * The Check API returns whether a given user has a relationship with a given object in a given store. The `user` field of the request can be a specific target, such as `user:anne`, or a userset (set of users) such as `group:marketing#member` or a type-bound public access `user:*`. To arrive at a result, the API uses: an authorization model, explicit tuples written through the Write API, contextual tuples present in the request, and implicit tuples that exist by virtue of applying set theory (such as `document:2021-budget#viewer@document:2021-budget#viewer`; the set of users who are viewers of `document:2021-budget` are the set of users who are the viewers of `document:2021-budget`). A `contextual_tuples` object may also be included in the body of the request. This object contains one field `tuple_keys`, which is an array of tuple keys. Each of these tuples may have an associated `condition`. You may also provide an `authorization_model_id` in the body. This will be used to assert that the input `tuple_key` is valid for the model specified. If not specified, the assertion will be made against the latest authorization model ID. It is strongly recommended to specify authorization model id for better performance. You may also provide a `context` object that will be used to evaluate the conditioned tuples in the system. It is strongly recommended to provide a value for all the input parameters of all the conditions, to ensure that all tuples be evaluated correctly. By default, the Check API caches results for a short time to optimize performance. You may specify a value of `HIGHER_CONSISTENCY` for the optional `consistency` parameter in the body to inform the server that higher conisistency is preferred at the expense of increased latency. Consideration should be given to the increased latency if requesting higher consistency. The response will return whether the relationship exists in the field `allowed`. Some exceptions apply, but in general, if a Check API responds with `{allowed: true}`, then you can expect the equivalent ListObjects query to return the object, and viceversa. For example, if `Check(user:anne, reader, document:2021-budget)` responds with `{allowed: true}`, then `ListObjects(user:anne, reader, document)` may include `document:2021-budget` in the response. ## Examples ### Querying with contextual tuples In order to check if user `user:anne` of type `user` has a `reader` relationship with object `document:2021-budget` given the following contextual tuple ```json { \"user\": \"user:anne\", \"relation\": \"member\", \"object\": \"time_slot:office_hours\" } ``` the Check API can be used with the following request body: ```json { \"tuple_key\": { \"user\": \"user:anne\", \"relation\": \"reader\", \"object\": \"document:2021-budget\" }, \"contextual_tuples\": { \"tuple_keys\": [ { \"user\": \"user:anne\", \"relation\": \"member\", \"object\": \"time_slot:office_hours\" } ] }, \"authorization_model_id\": \"01G50QVV17PECNVAHX1GG4Y5NC\" } ``` ### Querying usersets Some Checks will always return `true`, even without any tuples. For example, for the following authorization model ```python model schema 1.1 type user type document relations define reader: [user] ``` the following query ```json { \"tuple_key\": { \"user\": \"document:2021-budget#reader\", \"relation\": \"reader\", \"object\": \"document:2021-budget\" } } ``` will always return `{ \"allowed\": true }`. This is because usersets are self-defining: the userset `document:2021-budget#reader` will always have the `reader` relation with `document:2021-budget`. ### Querying usersets with difference in the model A Check for a userset can yield results that must be treated carefully if the model involves difference. For example, for the following authorization model ```python model schema 1.1 type user type group relations define member: [user] type document relations define blocked: [user] define reader: [group#member] but not blocked ``` the following query ```json { \"tuple_key\": { \"user\": \"group:finance#member\", \"relation\": \"reader\", \"object\": \"document:2021-budget\" }, \"contextual_tuples\": { \"tuple_keys\": [ { \"user\": \"user:anne\", \"relation\": \"member\", \"object\": \"group:finance\" }, { \"user\": \"group:finance#member\", \"relation\": \"reader\", \"object\": \"document:2021-budget\" }, { \"user\": \"user:anne\", \"relation\": \"blocked\", \"object\": \"document:2021-budget\" } ] }, } ``` will return `{ \"allowed\": true }`, even though a specific user of the userset `group:finance#member` does not have the `reader` relationship with the given object. ### Requesting higher consistency By default, the Check API caches results for a short time to optimize performance. You may request higher consistency to inform the server that higher consistency should be preferred at the expense of increased latency. Care should be taken when requesting higher consistency due to the increased latency. ```json { \"tuple_key\": { \"user\": \"group:finance#member\", \"relation\": \"reader\", \"object\": \"document:2021-budget\" }, \"consistency\": \"HIGHER_CONSISTENCY\" } ``` * @summary Check whether a user is authorized to access an object * @param {string} storeId * @param {CheckRequest} body @@ -299,7 +301,7 @@ export const OpenFgaApiAxiosParamCreator = function (configuration: Configuratio }; }, /** - * The ListObjects API returns a list of all the objects of the given type that the user has a relation with. To arrive at a result, the API uses: an authorization model, explicit tuples written through the Write API, contextual tuples present in the request, and implicit tuples that exist by virtue of applying set theory (such as `document:2021-budget#viewer@document:2021-budget#viewer`; the set of users who are viewers of `document:2021-budget` are the set of users who are the viewers of `document:2021-budget`). An `authorization_model_id` may be specified in the body. If it is not specified, the latest authorization model ID will be used. It is strongly recommended to specify authorization model id for better performance. You may also specify `contextual_tuples` that will be treated as regular tuples. Each of these tuples may have an associated `condition`. You may also provide a `context` object that will be used to evaluate the conditioned tuples in the system. It is strongly recommended to provide a value for all the input parameters of all the conditions, to ensure that all tuples be evaluated correctly. The response will contain the related objects in an array in the \"objects\" field of the response and they will be strings in the object format `:` (e.g. \"document:roadmap\"). The number of objects in the response array will be limited by the execution timeout specified in the flag OPENFGA_LIST_OBJECTS_DEADLINE and by the upper bound specified in the flag OPENFGA_LIST_OBJECTS_MAX_RESULTS, whichever is hit first. The objects given will not be sorted, and therefore two identical calls can give a given different set of objects. + * The ListObjects API returns a list of all the objects of the given type that the user has a relation with. To arrive at a result, the API uses: an authorization model, explicit tuples written through the Write API, contextual tuples present in the request, and implicit tuples that exist by virtue of applying set theory (such as `document:2021-budget#viewer@document:2021-budget#viewer`; the set of users who are viewers of `document:2021-budget` are the set of users who are the viewers of `document:2021-budget`). An `authorization_model_id` may be specified in the body. If it is not specified, the latest authorization model ID will be used. It is strongly recommended to specify authorization model id for better performance. You may also specify `contextual_tuples` that will be treated as regular tuples. Each of these tuples may have an associated `condition`. You may also provide a `context` object that will be used to evaluate the conditioned tuples in the system. It is strongly recommended to provide a value for all the input parameters of all the conditions, to ensure that all tuples be evaluated correctly. By default, the Check API caches results for a short time to optimize performance. You may specify a value of `HIGHER_CONSISTENCY` for the optional `consistency` parameter in the body to inform the server that higher conisistency is preferred at the expense of increased latency. Consideration should be given to the increased latency if requesting higher consistency. The response will contain the related objects in an array in the \"objects\" field of the response and they will be strings in the object format `:` (e.g. \"document:roadmap\"). The number of objects in the response array will be limited by the execution timeout specified in the flag OPENFGA_LIST_OBJECTS_DEADLINE and by the upper bound specified in the flag OPENFGA_LIST_OBJECTS_MAX_RESULTS, whichever is hit first. The objects given will not be sorted, and therefore two identical calls can give a given different set of objects. * @summary List all objects of the given type that the user has a relation with * @param {string} storeId * @param {ListObjectsRequest} body @@ -378,7 +380,7 @@ export const OpenFgaApiAxiosParamCreator = function (configuration: Configuratio }; }, /** - * The ListUsers API returns a list of all the users of a specific type that have a relation to a given object. To arrive at a result, the API uses: an authorization model, explicit tuples written through the Write API, contextual tuples present in the request, and implicit tuples that exist by virtue of applying set theory (such as `document:2021-budget#viewer@document:2021-budget#viewer`; the set of users who are viewers of `document:2021-budget` are the set of users who are the viewers of `document:2021-budget`). An `authorization_model_id` may be specified in the body. If it is not specified, the latest authorization model ID will be used. It is strongly recommended to specify authorization model id for better performance. You may also specify `contextual_tuples` that will be treated as regular tuples. Each of these tuples may have an associated `condition`. You may also provide a `context` object that will be used to evaluate the conditioned tuples in the system. It is strongly recommended to provide a value for all the input parameters of all the conditions, to ensure that all tuples be evaluated correctly. The response will contain the related users in an array in the \"users\" field of the response. These results may include specific objects, usersets or type-bound public access. Each of these types of results is encoded in its own type and not represented as a string.In cases where a type-bound public acces result is returned (e.g. `user:*`), it cannot be inferred that all subjects of that type have a relation to the object; it is possible that negations exist and checks should still be queried on individual subjects to ensure access to that document.The number of users in the response array will be limited by the execution timeout specified in the flag OPENFGA_LIST_USERS_DEADLINE and by the upper bound specified in the flag OPENFGA_LIST_USERS_MAX_RESULTS, whichever is hit first. The returned users will not be sorted, and therefore two identical calls may yield different sets of users. + * The ListUsers API returns a list of all the users of a specific type that have a relation to a given object. To arrive at a result, the API uses: an authorization model, explicit tuples written through the Write API, contextual tuples present in the request, and implicit tuples that exist by virtue of applying set theory (such as `document:2021-budget#viewer@document:2021-budget#viewer`; the set of users who are viewers of `document:2021-budget` are the set of users who are the viewers of `document:2021-budget`). An `authorization_model_id` may be specified in the body. If it is not specified, the latest authorization model ID will be used. It is strongly recommended to specify authorization model id for better performance. You may also specify `contextual_tuples` that will be treated as regular tuples. Each of these tuples may have an associated `condition`. You may also provide a `context` object that will be used to evaluate the conditioned tuples in the system. It is strongly recommended to provide a value for all the input parameters of all the conditions, to ensure that all tuples be evaluated correctly. The response will contain the related users in an array in the \"users\" field of the response. These results may include specific objects, usersets or type-bound public access. Each of these types of results is encoded in its own type and not represented as a string.In cases where a type-bound public access result is returned (e.g. `user:*`), it cannot be inferred that all subjects of that type have a relation to the object; it is possible that negations exist and checks should still be queried on individual subjects to ensure access to that document.The number of users in the response array will be limited by the execution timeout specified in the flag OPENFGA_LIST_USERS_DEADLINE and by the upper bound specified in the flag OPENFGA_LIST_USERS_MAX_RESULTS, whichever is hit first. The returned users will not be sorted, and therefore two identical calls may yield different sets of users. * @summary List the users matching the provided filter who have a certain relation to a particular type. * @param {string} storeId * @param {ListUsersRequest} body @@ -456,7 +458,7 @@ export const OpenFgaApiAxiosParamCreator = function (configuration: Configuratio }; }, /** - * The ReadAssertions API will return, for a given authorization model id, all the assertions stored for it. An assertion is an object that contains a tuple key, and the expectation of whether a call to the Check API of that tuple key will return true or false. + * The ReadAssertions API will return, for a given authorization model id, all the assertions stored for it. * @summary Read assertions for an authorization model ID * @param {string} storeId * @param {string} authorizationModelId @@ -658,7 +660,7 @@ export const OpenFgaApiAxiosParamCreator = function (configuration: Configuratio }; }, /** - * The WriteAssertions API will upsert new assertions for an authorization model id, or overwrite the existing ones. An assertion is an object that contains a tuple key, and the expectation of whether a call to the Check API of that tuple key will return true or false. + * The WriteAssertions API will upsert new assertions for an authorization model id, or overwrite the existing ones. An assertion is an object that contains a tuple key, the expectation of whether a call to the Check API of that tuple key will return true or false, and optionally a list of contextual tuples. * @summary Upsert assertions for an authorization model ID * @param {string} storeId * @param {string} authorizationModelId @@ -749,7 +751,7 @@ export const OpenFgaApiFp = function(configuration: Configuration, credentials: const localVarAxiosParamCreator = OpenFgaApiAxiosParamCreator(configuration, credentials); return { /** - * The Check API returns whether a given user has a relationship with a given object in a given store. The `user` field of the request can be a specific target, such as `user:anne`, or a userset (set of users) such as `group:marketing#member` or a type-bound public access `user:*`. To arrive at a result, the API uses: an authorization model, explicit tuples written through the Write API, contextual tuples present in the request, and implicit tuples that exist by virtue of applying set theory (such as `document:2021-budget#viewer@document:2021-budget#viewer`; the set of users who are viewers of `document:2021-budget` are the set of users who are the viewers of `document:2021-budget`). A `contextual_tuples` object may also be included in the body of the request. This object contains one field `tuple_keys`, which is an array of tuple keys. Each of these tuples may have an associated `condition`. You may also provide an `authorization_model_id` in the body. This will be used to assert that the input `tuple_key` is valid for the model specified. If not specified, the assertion will be made against the latest authorization model ID. It is strongly recommended to specify authorization model id for better performance. You may also provide a `context` object that will be used to evaluate the conditioned tuples in the system. It is strongly recommended to provide a value for all the input parameters of all the conditions, to ensure that all tuples be evaluated correctly. The response will return whether the relationship exists in the field `allowed`. Some exceptions apply, but in general, if a Check API responds with `{allowed: true}`, then you can expect the equivalent ListObjects query to return the object, and viceversa. For example, if `Check(user:anne, reader, document:2021-budget)` responds with `{allowed: true}`, then `ListObjects(user:anne, reader, document)` may include `document:2021-budget` in the response. ## Examples ### Querying with contextual tuples In order to check if user `user:anne` of type `user` has a `reader` relationship with object `document:2021-budget` given the following contextual tuple ```json { \"user\": \"user:anne\", \"relation\": \"member\", \"object\": \"time_slot:office_hours\" } ``` the Check API can be used with the following request body: ```json { \"tuple_key\": { \"user\": \"user:anne\", \"relation\": \"reader\", \"object\": \"document:2021-budget\" }, \"contextual_tuples\": { \"tuple_keys\": [ { \"user\": \"user:anne\", \"relation\": \"member\", \"object\": \"time_slot:office_hours\" } ] }, \"authorization_model_id\": \"01G50QVV17PECNVAHX1GG4Y5NC\" } ``` ### Querying usersets Some Checks will always return `true`, even without any tuples. For example, for the following authorization model ```python model schema 1.1 type user type document relations define reader: [user] ``` the following query ```json { \"tuple_key\": { \"user\": \"document:2021-budget#reader\", \"relation\": \"reader\", \"object\": \"document:2021-budget\" } } ``` will always return `{ \"allowed\": true }`. This is because usersets are self-defining: the userset `document:2021-budget#reader` will always have the `reader` relation with `document:2021-budget`. ### Querying usersets with difference in the model A Check for a userset can yield results that must be treated carefully if the model involves difference. For example, for the following authorization model ```python model schema 1.1 type user type group relations define member: [user] type document relations define blocked: [user] define reader: [group#member] but not blocked ``` the following query ```json { \"tuple_key\": { \"user\": \"group:finance#member\", \"relation\": \"reader\", \"object\": \"document:2021-budget\" }, \"contextual_tuples\": { \"tuple_keys\": [ { \"user\": \"user:anne\", \"relation\": \"member\", \"object\": \"group:finance\" }, { \"user\": \"group:finance#member\", \"relation\": \"reader\", \"object\": \"document:2021-budget\" }, { \"user\": \"user:anne\", \"relation\": \"blocked\", \"object\": \"document:2021-budget\" } ] }, } ``` will return `{ \"allowed\": true }`, even though a specific user of the userset `group:finance#member` does not have the `reader` relationship with the given object. + * The Check API returns whether a given user has a relationship with a given object in a given store. The `user` field of the request can be a specific target, such as `user:anne`, or a userset (set of users) such as `group:marketing#member` or a type-bound public access `user:*`. To arrive at a result, the API uses: an authorization model, explicit tuples written through the Write API, contextual tuples present in the request, and implicit tuples that exist by virtue of applying set theory (such as `document:2021-budget#viewer@document:2021-budget#viewer`; the set of users who are viewers of `document:2021-budget` are the set of users who are the viewers of `document:2021-budget`). A `contextual_tuples` object may also be included in the body of the request. This object contains one field `tuple_keys`, which is an array of tuple keys. Each of these tuples may have an associated `condition`. You may also provide an `authorization_model_id` in the body. This will be used to assert that the input `tuple_key` is valid for the model specified. If not specified, the assertion will be made against the latest authorization model ID. It is strongly recommended to specify authorization model id for better performance. You may also provide a `context` object that will be used to evaluate the conditioned tuples in the system. It is strongly recommended to provide a value for all the input parameters of all the conditions, to ensure that all tuples be evaluated correctly. By default, the Check API caches results for a short time to optimize performance. You may specify a value of `HIGHER_CONSISTENCY` for the optional `consistency` parameter in the body to inform the server that higher conisistency is preferred at the expense of increased latency. Consideration should be given to the increased latency if requesting higher consistency. The response will return whether the relationship exists in the field `allowed`. Some exceptions apply, but in general, if a Check API responds with `{allowed: true}`, then you can expect the equivalent ListObjects query to return the object, and viceversa. For example, if `Check(user:anne, reader, document:2021-budget)` responds with `{allowed: true}`, then `ListObjects(user:anne, reader, document)` may include `document:2021-budget` in the response. ## Examples ### Querying with contextual tuples In order to check if user `user:anne` of type `user` has a `reader` relationship with object `document:2021-budget` given the following contextual tuple ```json { \"user\": \"user:anne\", \"relation\": \"member\", \"object\": \"time_slot:office_hours\" } ``` the Check API can be used with the following request body: ```json { \"tuple_key\": { \"user\": \"user:anne\", \"relation\": \"reader\", \"object\": \"document:2021-budget\" }, \"contextual_tuples\": { \"tuple_keys\": [ { \"user\": \"user:anne\", \"relation\": \"member\", \"object\": \"time_slot:office_hours\" } ] }, \"authorization_model_id\": \"01G50QVV17PECNVAHX1GG4Y5NC\" } ``` ### Querying usersets Some Checks will always return `true`, even without any tuples. For example, for the following authorization model ```python model schema 1.1 type user type document relations define reader: [user] ``` the following query ```json { \"tuple_key\": { \"user\": \"document:2021-budget#reader\", \"relation\": \"reader\", \"object\": \"document:2021-budget\" } } ``` will always return `{ \"allowed\": true }`. This is because usersets are self-defining: the userset `document:2021-budget#reader` will always have the `reader` relation with `document:2021-budget`. ### Querying usersets with difference in the model A Check for a userset can yield results that must be treated carefully if the model involves difference. For example, for the following authorization model ```python model schema 1.1 type user type group relations define member: [user] type document relations define blocked: [user] define reader: [group#member] but not blocked ``` the following query ```json { \"tuple_key\": { \"user\": \"group:finance#member\", \"relation\": \"reader\", \"object\": \"document:2021-budget\" }, \"contextual_tuples\": { \"tuple_keys\": [ { \"user\": \"user:anne\", \"relation\": \"member\", \"object\": \"group:finance\" }, { \"user\": \"group:finance#member\", \"relation\": \"reader\", \"object\": \"document:2021-budget\" }, { \"user\": \"user:anne\", \"relation\": \"blocked\", \"object\": \"document:2021-budget\" } ] }, } ``` will return `{ \"allowed\": true }`, even though a specific user of the userset `group:finance#member` does not have the `reader` relationship with the given object. ### Requesting higher consistency By default, the Check API caches results for a short time to optimize performance. You may request higher consistency to inform the server that higher consistency should be preferred at the expense of increased latency. Care should be taken when requesting higher consistency due to the increased latency. ```json { \"tuple_key\": { \"user\": \"group:finance#member\", \"relation\": \"reader\", \"object\": \"document:2021-budget\" }, \"consistency\": \"HIGHER_CONSISTENCY\" } ``` * @summary Check whether a user is authorized to access an object * @param {string} storeId * @param {CheckRequest} body @@ -761,8 +763,7 @@ export const OpenFgaApiFp = function(configuration: Configuration, credentials: return createRequestFunction(localVarAxiosArgs, globalAxios, configuration, credentials, { [TelemetryAttribute.FgaClientRequestMethod]: "Check", [TelemetryAttribute.FgaClientRequestStoreId]: storeId ?? "", - [TelemetryAttribute.FgaClientRequestModelId]: body.authorization_model_id ?? "", - [TelemetryAttribute.FgaClientUser]: body.tuple_key.user + ...TelemetryAttributes.fromRequestBody(body) }); }, /** @@ -776,6 +777,7 @@ export const OpenFgaApiFp = function(configuration: Configuration, credentials: const localVarAxiosArgs = localVarAxiosParamCreator.createStore(body, options); return createRequestFunction(localVarAxiosArgs, globalAxios, configuration, credentials, { [TelemetryAttribute.FgaClientRequestMethod]: "CreateStore", + ...TelemetryAttributes.fromRequestBody(body) }); }, /** @@ -789,7 +791,7 @@ export const OpenFgaApiFp = function(configuration: Configuration, credentials: const localVarAxiosArgs = localVarAxiosParamCreator.deleteStore(storeId, options); return createRequestFunction(localVarAxiosArgs, globalAxios, configuration, credentials, { [TelemetryAttribute.FgaClientRequestMethod]: "DeleteStore", - [TelemetryAttribute.FgaClientRequestStoreId]: storeId, + [TelemetryAttribute.FgaClientRequestStoreId]: storeId ?? "", }); }, /** @@ -804,8 +806,8 @@ export const OpenFgaApiFp = function(configuration: Configuration, credentials: const localVarAxiosArgs = localVarAxiosParamCreator.expand(storeId, body, options); return createRequestFunction(localVarAxiosArgs, globalAxios, configuration, credentials, { [TelemetryAttribute.FgaClientRequestMethod]: "Expand", - [TelemetryAttribute.FgaClientRequestModelId]: body.authorization_model_id ?? "", [TelemetryAttribute.FgaClientRequestStoreId]: storeId ?? "", + ...TelemetryAttributes.fromRequestBody(body) }); }, /** @@ -819,11 +821,11 @@ export const OpenFgaApiFp = function(configuration: Configuration, credentials: const localVarAxiosArgs = localVarAxiosParamCreator.getStore(storeId, options); return createRequestFunction(localVarAxiosArgs, globalAxios, configuration, credentials, { [TelemetryAttribute.FgaClientRequestMethod]: "GetStore", - [TelemetryAttribute.FgaClientRequestStoreId]: storeId, + [TelemetryAttribute.FgaClientRequestStoreId]: storeId ?? "", }); }, /** - * The ListObjects API returns a list of all the objects of the given type that the user has a relation with. To arrive at a result, the API uses: an authorization model, explicit tuples written through the Write API, contextual tuples present in the request, and implicit tuples that exist by virtue of applying set theory (such as `document:2021-budget#viewer@document:2021-budget#viewer`; the set of users who are viewers of `document:2021-budget` are the set of users who are the viewers of `document:2021-budget`). An `authorization_model_id` may be specified in the body. If it is not specified, the latest authorization model ID will be used. It is strongly recommended to specify authorization model id for better performance. You may also specify `contextual_tuples` that will be treated as regular tuples. Each of these tuples may have an associated `condition`. You may also provide a `context` object that will be used to evaluate the conditioned tuples in the system. It is strongly recommended to provide a value for all the input parameters of all the conditions, to ensure that all tuples be evaluated correctly. The response will contain the related objects in an array in the \"objects\" field of the response and they will be strings in the object format `:` (e.g. \"document:roadmap\"). The number of objects in the response array will be limited by the execution timeout specified in the flag OPENFGA_LIST_OBJECTS_DEADLINE and by the upper bound specified in the flag OPENFGA_LIST_OBJECTS_MAX_RESULTS, whichever is hit first. The objects given will not be sorted, and therefore two identical calls can give a given different set of objects. + * The ListObjects API returns a list of all the objects of the given type that the user has a relation with. To arrive at a result, the API uses: an authorization model, explicit tuples written through the Write API, contextual tuples present in the request, and implicit tuples that exist by virtue of applying set theory (such as `document:2021-budget#viewer@document:2021-budget#viewer`; the set of users who are viewers of `document:2021-budget` are the set of users who are the viewers of `document:2021-budget`). An `authorization_model_id` may be specified in the body. If it is not specified, the latest authorization model ID will be used. It is strongly recommended to specify authorization model id for better performance. You may also specify `contextual_tuples` that will be treated as regular tuples. Each of these tuples may have an associated `condition`. You may also provide a `context` object that will be used to evaluate the conditioned tuples in the system. It is strongly recommended to provide a value for all the input parameters of all the conditions, to ensure that all tuples be evaluated correctly. By default, the Check API caches results for a short time to optimize performance. You may specify a value of `HIGHER_CONSISTENCY` for the optional `consistency` parameter in the body to inform the server that higher conisistency is preferred at the expense of increased latency. Consideration should be given to the increased latency if requesting higher consistency. The response will contain the related objects in an array in the \"objects\" field of the response and they will be strings in the object format `:` (e.g. \"document:roadmap\"). The number of objects in the response array will be limited by the execution timeout specified in the flag OPENFGA_LIST_OBJECTS_DEADLINE and by the upper bound specified in the flag OPENFGA_LIST_OBJECTS_MAX_RESULTS, whichever is hit first. The objects given will not be sorted, and therefore two identical calls can give a given different set of objects. * @summary List all objects of the given type that the user has a relation with * @param {string} storeId * @param {ListObjectsRequest} body @@ -835,12 +837,11 @@ export const OpenFgaApiFp = function(configuration: Configuration, credentials: return createRequestFunction(localVarAxiosArgs, globalAxios, configuration, credentials, { [TelemetryAttribute.FgaClientRequestMethod]: "ListObjects", [TelemetryAttribute.FgaClientRequestStoreId]: storeId ?? "", - [TelemetryAttribute.FgaClientRequestModelId]: body.authorization_model_id ?? "", - [TelemetryAttribute.FgaClientUser]: body.user + ...TelemetryAttributes.fromRequestBody(body) }); }, /** - * Returns a paginated list of OpenFGA stores and a continuation token to get additional stores. The continuation token will be empty if there are no more stores. + * Returns a paginated list of OpenFGA stores and a continuation token to get additional stores. The continuation token will be empty if there are no more stores. * @summary List all stores * @param {number} [pageSize] * @param {string} [continuationToken] @@ -854,7 +855,7 @@ export const OpenFgaApiFp = function(configuration: Configuration, credentials: }); }, /** - * The ListUsers API returns a list of all the users of a specific type that have a relation to a given object. To arrive at a result, the API uses: an authorization model, explicit tuples written through the Write API, contextual tuples present in the request, and implicit tuples that exist by virtue of applying set theory (such as `document:2021-budget#viewer@document:2021-budget#viewer`; the set of users who are viewers of `document:2021-budget` are the set of users who are the viewers of `document:2021-budget`). An `authorization_model_id` may be specified in the body. If it is not specified, the latest authorization model ID will be used. It is strongly recommended to specify authorization model id for better performance. You may also specify `contextual_tuples` that will be treated as regular tuples. Each of these tuples may have an associated `condition`. You may also provide a `context` object that will be used to evaluate the conditioned tuples in the system. It is strongly recommended to provide a value for all the input parameters of all the conditions, to ensure that all tuples be evaluated correctly. The response will contain the related users in an array in the \"users\" field of the response. These results may include specific objects, usersets or type-bound public access. Each of these types of results is encoded in its own type and not represented as a string.In cases where a type-bound public acces result is returned (e.g. `user:*`), it cannot be inferred that all subjects of that type have a relation to the object; it is possible that negations exist and checks should still be queried on individual subjects to ensure access to that document.The number of users in the response array will be limited by the execution timeout specified in the flag OPENFGA_LIST_USERS_DEADLINE and by the upper bound specified in the flag OPENFGA_LIST_USERS_MAX_RESULTS, whichever is hit first. The returned users will not be sorted, and therefore two identical calls may yield different sets of users. + * The ListUsers API returns a list of all the users of a specific type that have a relation to a given object. To arrive at a result, the API uses: an authorization model, explicit tuples written through the Write API, contextual tuples present in the request, and implicit tuples that exist by virtue of applying set theory (such as `document:2021-budget#viewer@document:2021-budget#viewer`; the set of users who are viewers of `document:2021-budget` are the set of users who are the viewers of `document:2021-budget`). An `authorization_model_id` may be specified in the body. If it is not specified, the latest authorization model ID will be used. It is strongly recommended to specify authorization model id for better performance. You may also specify `contextual_tuples` that will be treated as regular tuples. Each of these tuples may have an associated `condition`. You may also provide a `context` object that will be used to evaluate the conditioned tuples in the system. It is strongly recommended to provide a value for all the input parameters of all the conditions, to ensure that all tuples be evaluated correctly. The response will contain the related users in an array in the \"users\" field of the response. These results may include specific objects, usersets or type-bound public access. Each of these types of results is encoded in its own type and not represented as a string.In cases where a type-bound public access result is returned (e.g. `user:*`), it cannot be inferred that all subjects of that type have a relation to the object; it is possible that negations exist and checks should still be queried on individual subjects to ensure access to that document.The number of users in the response array will be limited by the execution timeout specified in the flag OPENFGA_LIST_USERS_DEADLINE and by the upper bound specified in the flag OPENFGA_LIST_USERS_MAX_RESULTS, whichever is hit first. The returned users will not be sorted, and therefore two identical calls may yield different sets of users. * @summary List the users matching the provided filter who have a certain relation to a particular type. * @param {string} storeId * @param {ListUsersRequest} body @@ -866,7 +867,7 @@ export const OpenFgaApiFp = function(configuration: Configuration, credentials: return createRequestFunction(localVarAxiosArgs, globalAxios, configuration, credentials, { [TelemetryAttribute.FgaClientRequestMethod]: "ListUsers", [TelemetryAttribute.FgaClientRequestStoreId]: storeId ?? "", - [TelemetryAttribute.FgaClientRequestModelId]: body.authorization_model_id ?? "", + ...TelemetryAttributes.fromRequestBody(body) }); }, /** @@ -881,11 +882,12 @@ export const OpenFgaApiFp = function(configuration: Configuration, credentials: const localVarAxiosArgs = localVarAxiosParamCreator.read(storeId, body, options); return createRequestFunction(localVarAxiosArgs, globalAxios, configuration, credentials, { [TelemetryAttribute.FgaClientRequestMethod]: "Read", - [TelemetryAttribute.FgaClientRequestStoreId]: storeId, + [TelemetryAttribute.FgaClientRequestStoreId]: storeId ?? "", + ...TelemetryAttributes.fromRequestBody(body) }); }, /** - * The ReadAssertions API will return, for a given authorization model id, all the assertions stored for it. An assertion is an object that contains a tuple key, and the expectation of whether a call to the Check API of that tuple key will return true or false. + * The ReadAssertions API will return, for a given authorization model id, all the assertions stored for it. * @summary Read assertions for an authorization model ID * @param {string} storeId * @param {string} authorizationModelId @@ -896,8 +898,7 @@ export const OpenFgaApiFp = function(configuration: Configuration, credentials: const localVarAxiosArgs = localVarAxiosParamCreator.readAssertions(storeId, authorizationModelId, options); return createRequestFunction(localVarAxiosArgs, globalAxios, configuration, credentials, { [TelemetryAttribute.FgaClientRequestMethod]: "ReadAssertions", - [TelemetryAttribute.FgaClientRequestStoreId]: storeId, - [TelemetryAttribute.FgaClientRequestModelId]: authorizationModelId, + [TelemetryAttribute.FgaClientRequestStoreId]: storeId ?? "", }); }, /** @@ -912,7 +913,7 @@ export const OpenFgaApiFp = function(configuration: Configuration, credentials: const localVarAxiosArgs = localVarAxiosParamCreator.readAuthorizationModel(storeId, id, options); return createRequestFunction(localVarAxiosArgs, globalAxios, configuration, credentials, { [TelemetryAttribute.FgaClientRequestMethod]: "ReadAuthorizationModel", - [TelemetryAttribute.FgaClientRequestStoreId]: storeId, + [TelemetryAttribute.FgaClientRequestStoreId]: storeId ?? "", }); }, /** @@ -928,7 +929,7 @@ export const OpenFgaApiFp = function(configuration: Configuration, credentials: const localVarAxiosArgs = localVarAxiosParamCreator.readAuthorizationModels(storeId, pageSize, continuationToken, options); return createRequestFunction(localVarAxiosArgs, globalAxios, configuration, credentials, { [TelemetryAttribute.FgaClientRequestMethod]: "ReadAuthorizationModels", - [TelemetryAttribute.FgaClientRequestStoreId]: storeId, + [TelemetryAttribute.FgaClientRequestStoreId]: storeId ?? "", }); }, /** @@ -945,7 +946,7 @@ export const OpenFgaApiFp = function(configuration: Configuration, credentials: const localVarAxiosArgs = localVarAxiosParamCreator.readChanges(storeId, type, pageSize, continuationToken, options); return createRequestFunction(localVarAxiosArgs, globalAxios, configuration, credentials, { [TelemetryAttribute.FgaClientRequestMethod]: "ReadChanges", - [TelemetryAttribute.FgaClientRequestStoreId]: storeId, + [TelemetryAttribute.FgaClientRequestStoreId]: storeId ?? "", }); }, /** @@ -961,11 +962,11 @@ export const OpenFgaApiFp = function(configuration: Configuration, credentials: return createRequestFunction(localVarAxiosArgs, globalAxios, configuration, credentials, { [TelemetryAttribute.FgaClientRequestMethod]: "Write", [TelemetryAttribute.FgaClientRequestStoreId]: storeId ?? "", - [TelemetryAttribute.FgaClientRequestModelId]: body.authorization_model_id ?? "", + ...TelemetryAttributes.fromRequestBody(body) }); }, /** - * The WriteAssertions API will upsert new assertions for an authorization model id, or overwrite the existing ones. An assertion is an object that contains a tuple key, and the expectation of whether a call to the Check API of that tuple key will return true or false. + * The WriteAssertions API will upsert new assertions for an authorization model id, or overwrite the existing ones. An assertion is an object that contains a tuple key, the expectation of whether a call to the Check API of that tuple key will return true or false, and optionally a list of contextual tuples. * @summary Upsert assertions for an authorization model ID * @param {string} storeId * @param {string} authorizationModelId @@ -977,8 +978,8 @@ export const OpenFgaApiFp = function(configuration: Configuration, credentials: const localVarAxiosArgs = localVarAxiosParamCreator.writeAssertions(storeId, authorizationModelId, body, options); return createRequestFunction(localVarAxiosArgs, globalAxios, configuration, credentials, { [TelemetryAttribute.FgaClientRequestMethod]: "WriteAssertions", - [TelemetryAttribute.FgaClientRequestStoreId]: storeId, - [TelemetryAttribute.FgaClientRequestModelId]: authorizationModelId, + [TelemetryAttribute.FgaClientRequestStoreId]: storeId ?? "", + ...TelemetryAttributes.fromRequestBody(body) }); }, /** @@ -993,7 +994,8 @@ export const OpenFgaApiFp = function(configuration: Configuration, credentials: const localVarAxiosArgs = localVarAxiosParamCreator.writeAuthorizationModel(storeId, body, options); return createRequestFunction(localVarAxiosArgs, globalAxios, configuration, credentials, { [TelemetryAttribute.FgaClientRequestMethod]: "WriteAuthorizationModel", - [TelemetryAttribute.FgaClientRequestStoreId]: storeId, + [TelemetryAttribute.FgaClientRequestStoreId]: storeId ?? "", + ...TelemetryAttributes.fromRequestBody(body) }); }, }; @@ -1007,7 +1009,7 @@ export const OpenFgaApiFactory = function (configuration: Configuration, credent const localVarFp = OpenFgaApiFp(configuration, credentials); return { /** - * The Check API returns whether a given user has a relationship with a given object in a given store. The `user` field of the request can be a specific target, such as `user:anne`, or a userset (set of users) such as `group:marketing#member` or a type-bound public access `user:*`. To arrive at a result, the API uses: an authorization model, explicit tuples written through the Write API, contextual tuples present in the request, and implicit tuples that exist by virtue of applying set theory (such as `document:2021-budget#viewer@document:2021-budget#viewer`; the set of users who are viewers of `document:2021-budget` are the set of users who are the viewers of `document:2021-budget`). A `contextual_tuples` object may also be included in the body of the request. This object contains one field `tuple_keys`, which is an array of tuple keys. Each of these tuples may have an associated `condition`. You may also provide an `authorization_model_id` in the body. This will be used to assert that the input `tuple_key` is valid for the model specified. If not specified, the assertion will be made against the latest authorization model ID. It is strongly recommended to specify authorization model id for better performance. You may also provide a `context` object that will be used to evaluate the conditioned tuples in the system. It is strongly recommended to provide a value for all the input parameters of all the conditions, to ensure that all tuples be evaluated correctly. The response will return whether the relationship exists in the field `allowed`. Some exceptions apply, but in general, if a Check API responds with `{allowed: true}`, then you can expect the equivalent ListObjects query to return the object, and viceversa. For example, if `Check(user:anne, reader, document:2021-budget)` responds with `{allowed: true}`, then `ListObjects(user:anne, reader, document)` may include `document:2021-budget` in the response. ## Examples ### Querying with contextual tuples In order to check if user `user:anne` of type `user` has a `reader` relationship with object `document:2021-budget` given the following contextual tuple ```json { \"user\": \"user:anne\", \"relation\": \"member\", \"object\": \"time_slot:office_hours\" } ``` the Check API can be used with the following request body: ```json { \"tuple_key\": { \"user\": \"user:anne\", \"relation\": \"reader\", \"object\": \"document:2021-budget\" }, \"contextual_tuples\": { \"tuple_keys\": [ { \"user\": \"user:anne\", \"relation\": \"member\", \"object\": \"time_slot:office_hours\" } ] }, \"authorization_model_id\": \"01G50QVV17PECNVAHX1GG4Y5NC\" } ``` ### Querying usersets Some Checks will always return `true`, even without any tuples. For example, for the following authorization model ```python model schema 1.1 type user type document relations define reader: [user] ``` the following query ```json { \"tuple_key\": { \"user\": \"document:2021-budget#reader\", \"relation\": \"reader\", \"object\": \"document:2021-budget\" } } ``` will always return `{ \"allowed\": true }`. This is because usersets are self-defining: the userset `document:2021-budget#reader` will always have the `reader` relation with `document:2021-budget`. ### Querying usersets with difference in the model A Check for a userset can yield results that must be treated carefully if the model involves difference. For example, for the following authorization model ```python model schema 1.1 type user type group relations define member: [user] type document relations define blocked: [user] define reader: [group#member] but not blocked ``` the following query ```json { \"tuple_key\": { \"user\": \"group:finance#member\", \"relation\": \"reader\", \"object\": \"document:2021-budget\" }, \"contextual_tuples\": { \"tuple_keys\": [ { \"user\": \"user:anne\", \"relation\": \"member\", \"object\": \"group:finance\" }, { \"user\": \"group:finance#member\", \"relation\": \"reader\", \"object\": \"document:2021-budget\" }, { \"user\": \"user:anne\", \"relation\": \"blocked\", \"object\": \"document:2021-budget\" } ] }, } ``` will return `{ \"allowed\": true }`, even though a specific user of the userset `group:finance#member` does not have the `reader` relationship with the given object. + * The Check API returns whether a given user has a relationship with a given object in a given store. The `user` field of the request can be a specific target, such as `user:anne`, or a userset (set of users) such as `group:marketing#member` or a type-bound public access `user:*`. To arrive at a result, the API uses: an authorization model, explicit tuples written through the Write API, contextual tuples present in the request, and implicit tuples that exist by virtue of applying set theory (such as `document:2021-budget#viewer@document:2021-budget#viewer`; the set of users who are viewers of `document:2021-budget` are the set of users who are the viewers of `document:2021-budget`). A `contextual_tuples` object may also be included in the body of the request. This object contains one field `tuple_keys`, which is an array of tuple keys. Each of these tuples may have an associated `condition`. You may also provide an `authorization_model_id` in the body. This will be used to assert that the input `tuple_key` is valid for the model specified. If not specified, the assertion will be made against the latest authorization model ID. It is strongly recommended to specify authorization model id for better performance. You may also provide a `context` object that will be used to evaluate the conditioned tuples in the system. It is strongly recommended to provide a value for all the input parameters of all the conditions, to ensure that all tuples be evaluated correctly. By default, the Check API caches results for a short time to optimize performance. You may specify a value of `HIGHER_CONSISTENCY` for the optional `consistency` parameter in the body to inform the server that higher conisistency is preferred at the expense of increased latency. Consideration should be given to the increased latency if requesting higher consistency. The response will return whether the relationship exists in the field `allowed`. Some exceptions apply, but in general, if a Check API responds with `{allowed: true}`, then you can expect the equivalent ListObjects query to return the object, and viceversa. For example, if `Check(user:anne, reader, document:2021-budget)` responds with `{allowed: true}`, then `ListObjects(user:anne, reader, document)` may include `document:2021-budget` in the response. ## Examples ### Querying with contextual tuples In order to check if user `user:anne` of type `user` has a `reader` relationship with object `document:2021-budget` given the following contextual tuple ```json { \"user\": \"user:anne\", \"relation\": \"member\", \"object\": \"time_slot:office_hours\" } ``` the Check API can be used with the following request body: ```json { \"tuple_key\": { \"user\": \"user:anne\", \"relation\": \"reader\", \"object\": \"document:2021-budget\" }, \"contextual_tuples\": { \"tuple_keys\": [ { \"user\": \"user:anne\", \"relation\": \"member\", \"object\": \"time_slot:office_hours\" } ] }, \"authorization_model_id\": \"01G50QVV17PECNVAHX1GG4Y5NC\" } ``` ### Querying usersets Some Checks will always return `true`, even without any tuples. For example, for the following authorization model ```python model schema 1.1 type user type document relations define reader: [user] ``` the following query ```json { \"tuple_key\": { \"user\": \"document:2021-budget#reader\", \"relation\": \"reader\", \"object\": \"document:2021-budget\" } } ``` will always return `{ \"allowed\": true }`. This is because usersets are self-defining: the userset `document:2021-budget#reader` will always have the `reader` relation with `document:2021-budget`. ### Querying usersets with difference in the model A Check for a userset can yield results that must be treated carefully if the model involves difference. For example, for the following authorization model ```python model schema 1.1 type user type group relations define member: [user] type document relations define blocked: [user] define reader: [group#member] but not blocked ``` the following query ```json { \"tuple_key\": { \"user\": \"group:finance#member\", \"relation\": \"reader\", \"object\": \"document:2021-budget\" }, \"contextual_tuples\": { \"tuple_keys\": [ { \"user\": \"user:anne\", \"relation\": \"member\", \"object\": \"group:finance\" }, { \"user\": \"group:finance#member\", \"relation\": \"reader\", \"object\": \"document:2021-budget\" }, { \"user\": \"user:anne\", \"relation\": \"blocked\", \"object\": \"document:2021-budget\" } ] }, } ``` will return `{ \"allowed\": true }`, even though a specific user of the userset `group:finance#member` does not have the `reader` relationship with the given object. ### Requesting higher consistency By default, the Check API caches results for a short time to optimize performance. You may request higher consistency to inform the server that higher consistency should be preferred at the expense of increased latency. Care should be taken when requesting higher consistency due to the increased latency. ```json { \"tuple_key\": { \"user\": \"group:finance#member\", \"relation\": \"reader\", \"object\": \"document:2021-budget\" }, \"consistency\": \"HIGHER_CONSISTENCY\" } ``` * @summary Check whether a user is authorized to access an object * @param {string} storeId * @param {CheckRequest} body @@ -1059,7 +1061,7 @@ export const OpenFgaApiFactory = function (configuration: Configuration, credent return localVarFp.getStore(storeId, options).then((request) => request(axios)); }, /** - * The ListObjects API returns a list of all the objects of the given type that the user has a relation with. To arrive at a result, the API uses: an authorization model, explicit tuples written through the Write API, contextual tuples present in the request, and implicit tuples that exist by virtue of applying set theory (such as `document:2021-budget#viewer@document:2021-budget#viewer`; the set of users who are viewers of `document:2021-budget` are the set of users who are the viewers of `document:2021-budget`). An `authorization_model_id` may be specified in the body. If it is not specified, the latest authorization model ID will be used. It is strongly recommended to specify authorization model id for better performance. You may also specify `contextual_tuples` that will be treated as regular tuples. Each of these tuples may have an associated `condition`. You may also provide a `context` object that will be used to evaluate the conditioned tuples in the system. It is strongly recommended to provide a value for all the input parameters of all the conditions, to ensure that all tuples be evaluated correctly. The response will contain the related objects in an array in the \"objects\" field of the response and they will be strings in the object format `:` (e.g. \"document:roadmap\"). The number of objects in the response array will be limited by the execution timeout specified in the flag OPENFGA_LIST_OBJECTS_DEADLINE and by the upper bound specified in the flag OPENFGA_LIST_OBJECTS_MAX_RESULTS, whichever is hit first. The objects given will not be sorted, and therefore two identical calls can give a given different set of objects. + * The ListObjects API returns a list of all the objects of the given type that the user has a relation with. To arrive at a result, the API uses: an authorization model, explicit tuples written through the Write API, contextual tuples present in the request, and implicit tuples that exist by virtue of applying set theory (such as `document:2021-budget#viewer@document:2021-budget#viewer`; the set of users who are viewers of `document:2021-budget` are the set of users who are the viewers of `document:2021-budget`). An `authorization_model_id` may be specified in the body. If it is not specified, the latest authorization model ID will be used. It is strongly recommended to specify authorization model id for better performance. You may also specify `contextual_tuples` that will be treated as regular tuples. Each of these tuples may have an associated `condition`. You may also provide a `context` object that will be used to evaluate the conditioned tuples in the system. It is strongly recommended to provide a value for all the input parameters of all the conditions, to ensure that all tuples be evaluated correctly. By default, the Check API caches results for a short time to optimize performance. You may specify a value of `HIGHER_CONSISTENCY` for the optional `consistency` parameter in the body to inform the server that higher conisistency is preferred at the expense of increased latency. Consideration should be given to the increased latency if requesting higher consistency. The response will contain the related objects in an array in the \"objects\" field of the response and they will be strings in the object format `:` (e.g. \"document:roadmap\"). The number of objects in the response array will be limited by the execution timeout specified in the flag OPENFGA_LIST_OBJECTS_DEADLINE and by the upper bound specified in the flag OPENFGA_LIST_OBJECTS_MAX_RESULTS, whichever is hit first. The objects given will not be sorted, and therefore two identical calls can give a given different set of objects. * @summary List all objects of the given type that the user has a relation with * @param {string} storeId * @param {ListObjectsRequest} body @@ -1081,7 +1083,7 @@ export const OpenFgaApiFactory = function (configuration: Configuration, credent return localVarFp.listStores(pageSize, continuationToken, options).then((request) => request(axios)); }, /** - * The ListUsers API returns a list of all the users of a specific type that have a relation to a given object. To arrive at a result, the API uses: an authorization model, explicit tuples written through the Write API, contextual tuples present in the request, and implicit tuples that exist by virtue of applying set theory (such as `document:2021-budget#viewer@document:2021-budget#viewer`; the set of users who are viewers of `document:2021-budget` are the set of users who are the viewers of `document:2021-budget`). An `authorization_model_id` may be specified in the body. If it is not specified, the latest authorization model ID will be used. It is strongly recommended to specify authorization model id for better performance. You may also specify `contextual_tuples` that will be treated as regular tuples. Each of these tuples may have an associated `condition`. You may also provide a `context` object that will be used to evaluate the conditioned tuples in the system. It is strongly recommended to provide a value for all the input parameters of all the conditions, to ensure that all tuples be evaluated correctly. The response will contain the related users in an array in the \"users\" field of the response. These results may include specific objects, usersets or type-bound public access. Each of these types of results is encoded in its own type and not represented as a string.In cases where a type-bound public acces result is returned (e.g. `user:*`), it cannot be inferred that all subjects of that type have a relation to the object; it is possible that negations exist and checks should still be queried on individual subjects to ensure access to that document.The number of users in the response array will be limited by the execution timeout specified in the flag OPENFGA_LIST_USERS_DEADLINE and by the upper bound specified in the flag OPENFGA_LIST_USERS_MAX_RESULTS, whichever is hit first. The returned users will not be sorted, and therefore two identical calls may yield different sets of users. + * The ListUsers API returns a list of all the users of a specific type that have a relation to a given object. To arrive at a result, the API uses: an authorization model, explicit tuples written through the Write API, contextual tuples present in the request, and implicit tuples that exist by virtue of applying set theory (such as `document:2021-budget#viewer@document:2021-budget#viewer`; the set of users who are viewers of `document:2021-budget` are the set of users who are the viewers of `document:2021-budget`). An `authorization_model_id` may be specified in the body. If it is not specified, the latest authorization model ID will be used. It is strongly recommended to specify authorization model id for better performance. You may also specify `contextual_tuples` that will be treated as regular tuples. Each of these tuples may have an associated `condition`. You may also provide a `context` object that will be used to evaluate the conditioned tuples in the system. It is strongly recommended to provide a value for all the input parameters of all the conditions, to ensure that all tuples be evaluated correctly. The response will contain the related users in an array in the \"users\" field of the response. These results may include specific objects, usersets or type-bound public access. Each of these types of results is encoded in its own type and not represented as a string.In cases where a type-bound public access result is returned (e.g. `user:*`), it cannot be inferred that all subjects of that type have a relation to the object; it is possible that negations exist and checks should still be queried on individual subjects to ensure access to that document.The number of users in the response array will be limited by the execution timeout specified in the flag OPENFGA_LIST_USERS_DEADLINE and by the upper bound specified in the flag OPENFGA_LIST_USERS_MAX_RESULTS, whichever is hit first. The returned users will not be sorted, and therefore two identical calls may yield different sets of users. * @summary List the users matching the provided filter who have a certain relation to a particular type. * @param {string} storeId * @param {ListUsersRequest} body @@ -1103,7 +1105,7 @@ export const OpenFgaApiFactory = function (configuration: Configuration, credent return localVarFp.read(storeId, body, options).then((request) => request(axios)); }, /** - * The ReadAssertions API will return, for a given authorization model id, all the assertions stored for it. An assertion is an object that contains a tuple key, and the expectation of whether a call to the Check API of that tuple key will return true or false. + * The ReadAssertions API will return, for a given authorization model id, all the assertions stored for it. * @summary Read assertions for an authorization model ID * @param {string} storeId * @param {string} authorizationModelId @@ -1161,7 +1163,7 @@ export const OpenFgaApiFactory = function (configuration: Configuration, credent return localVarFp.write(storeId, body, options).then((request) => request(axios)); }, /** - * The WriteAssertions API will upsert new assertions for an authorization model id, or overwrite the existing ones. An assertion is an object that contains a tuple key, and the expectation of whether a call to the Check API of that tuple key will return true or false. + * The WriteAssertions API will upsert new assertions for an authorization model id, or overwrite the existing ones. An assertion is an object that contains a tuple key, the expectation of whether a call to the Check API of that tuple key will return true or false, and optionally a list of contextual tuples. * @summary Upsert assertions for an authorization model ID * @param {string} storeId * @param {string} authorizationModelId @@ -1194,7 +1196,7 @@ export const OpenFgaApiFactory = function (configuration: Configuration, credent */ export class OpenFgaApi extends BaseAPI { /** - * The Check API returns whether a given user has a relationship with a given object in a given store. The `user` field of the request can be a specific target, such as `user:anne`, or a userset (set of users) such as `group:marketing#member` or a type-bound public access `user:*`. To arrive at a result, the API uses: an authorization model, explicit tuples written through the Write API, contextual tuples present in the request, and implicit tuples that exist by virtue of applying set theory (such as `document:2021-budget#viewer@document:2021-budget#viewer`; the set of users who are viewers of `document:2021-budget` are the set of users who are the viewers of `document:2021-budget`). A `contextual_tuples` object may also be included in the body of the request. This object contains one field `tuple_keys`, which is an array of tuple keys. Each of these tuples may have an associated `condition`. You may also provide an `authorization_model_id` in the body. This will be used to assert that the input `tuple_key` is valid for the model specified. If not specified, the assertion will be made against the latest authorization model ID. It is strongly recommended to specify authorization model id for better performance. You may also provide a `context` object that will be used to evaluate the conditioned tuples in the system. It is strongly recommended to provide a value for all the input parameters of all the conditions, to ensure that all tuples be evaluated correctly. The response will return whether the relationship exists in the field `allowed`. Some exceptions apply, but in general, if a Check API responds with `{allowed: true}`, then you can expect the equivalent ListObjects query to return the object, and viceversa. For example, if `Check(user:anne, reader, document:2021-budget)` responds with `{allowed: true}`, then `ListObjects(user:anne, reader, document)` may include `document:2021-budget` in the response. ## Examples ### Querying with contextual tuples In order to check if user `user:anne` of type `user` has a `reader` relationship with object `document:2021-budget` given the following contextual tuple ```json { \"user\": \"user:anne\", \"relation\": \"member\", \"object\": \"time_slot:office_hours\" } ``` the Check API can be used with the following request body: ```json { \"tuple_key\": { \"user\": \"user:anne\", \"relation\": \"reader\", \"object\": \"document:2021-budget\" }, \"contextual_tuples\": { \"tuple_keys\": [ { \"user\": \"user:anne\", \"relation\": \"member\", \"object\": \"time_slot:office_hours\" } ] }, \"authorization_model_id\": \"01G50QVV17PECNVAHX1GG4Y5NC\" } ``` ### Querying usersets Some Checks will always return `true`, even without any tuples. For example, for the following authorization model ```python model schema 1.1 type user type document relations define reader: [user] ``` the following query ```json { \"tuple_key\": { \"user\": \"document:2021-budget#reader\", \"relation\": \"reader\", \"object\": \"document:2021-budget\" } } ``` will always return `{ \"allowed\": true }`. This is because usersets are self-defining: the userset `document:2021-budget#reader` will always have the `reader` relation with `document:2021-budget`. ### Querying usersets with difference in the model A Check for a userset can yield results that must be treated carefully if the model involves difference. For example, for the following authorization model ```python model schema 1.1 type user type group relations define member: [user] type document relations define blocked: [user] define reader: [group#member] but not blocked ``` the following query ```json { \"tuple_key\": { \"user\": \"group:finance#member\", \"relation\": \"reader\", \"object\": \"document:2021-budget\" }, \"contextual_tuples\": { \"tuple_keys\": [ { \"user\": \"user:anne\", \"relation\": \"member\", \"object\": \"group:finance\" }, { \"user\": \"group:finance#member\", \"relation\": \"reader\", \"object\": \"document:2021-budget\" }, { \"user\": \"user:anne\", \"relation\": \"blocked\", \"object\": \"document:2021-budget\" } ] }, } ``` will return `{ \"allowed\": true }`, even though a specific user of the userset `group:finance#member` does not have the `reader` relationship with the given object. + * The Check API returns whether a given user has a relationship with a given object in a given store. The `user` field of the request can be a specific target, such as `user:anne`, or a userset (set of users) such as `group:marketing#member` or a type-bound public access `user:*`. To arrive at a result, the API uses: an authorization model, explicit tuples written through the Write API, contextual tuples present in the request, and implicit tuples that exist by virtue of applying set theory (such as `document:2021-budget#viewer@document:2021-budget#viewer`; the set of users who are viewers of `document:2021-budget` are the set of users who are the viewers of `document:2021-budget`). A `contextual_tuples` object may also be included in the body of the request. This object contains one field `tuple_keys`, which is an array of tuple keys. Each of these tuples may have an associated `condition`. You may also provide an `authorization_model_id` in the body. This will be used to assert that the input `tuple_key` is valid for the model specified. If not specified, the assertion will be made against the latest authorization model ID. It is strongly recommended to specify authorization model id for better performance. You may also provide a `context` object that will be used to evaluate the conditioned tuples in the system. It is strongly recommended to provide a value for all the input parameters of all the conditions, to ensure that all tuples be evaluated correctly. By default, the Check API caches results for a short time to optimize performance. You may specify a value of `HIGHER_CONSISTENCY` for the optional `consistency` parameter in the body to inform the server that higher conisistency is preferred at the expense of increased latency. Consideration should be given to the increased latency if requesting higher consistency. The response will return whether the relationship exists in the field `allowed`. Some exceptions apply, but in general, if a Check API responds with `{allowed: true}`, then you can expect the equivalent ListObjects query to return the object, and viceversa. For example, if `Check(user:anne, reader, document:2021-budget)` responds with `{allowed: true}`, then `ListObjects(user:anne, reader, document)` may include `document:2021-budget` in the response. ## Examples ### Querying with contextual tuples In order to check if user `user:anne` of type `user` has a `reader` relationship with object `document:2021-budget` given the following contextual tuple ```json { \"user\": \"user:anne\", \"relation\": \"member\", \"object\": \"time_slot:office_hours\" } ``` the Check API can be used with the following request body: ```json { \"tuple_key\": { \"user\": \"user:anne\", \"relation\": \"reader\", \"object\": \"document:2021-budget\" }, \"contextual_tuples\": { \"tuple_keys\": [ { \"user\": \"user:anne\", \"relation\": \"member\", \"object\": \"time_slot:office_hours\" } ] }, \"authorization_model_id\": \"01G50QVV17PECNVAHX1GG4Y5NC\" } ``` ### Querying usersets Some Checks will always return `true`, even without any tuples. For example, for the following authorization model ```python model schema 1.1 type user type document relations define reader: [user] ``` the following query ```json { \"tuple_key\": { \"user\": \"document:2021-budget#reader\", \"relation\": \"reader\", \"object\": \"document:2021-budget\" } } ``` will always return `{ \"allowed\": true }`. This is because usersets are self-defining: the userset `document:2021-budget#reader` will always have the `reader` relation with `document:2021-budget`. ### Querying usersets with difference in the model A Check for a userset can yield results that must be treated carefully if the model involves difference. For example, for the following authorization model ```python model schema 1.1 type user type group relations define member: [user] type document relations define blocked: [user] define reader: [group#member] but not blocked ``` the following query ```json { \"tuple_key\": { \"user\": \"group:finance#member\", \"relation\": \"reader\", \"object\": \"document:2021-budget\" }, \"contextual_tuples\": { \"tuple_keys\": [ { \"user\": \"user:anne\", \"relation\": \"member\", \"object\": \"group:finance\" }, { \"user\": \"group:finance#member\", \"relation\": \"reader\", \"object\": \"document:2021-budget\" }, { \"user\": \"user:anne\", \"relation\": \"blocked\", \"object\": \"document:2021-budget\" } ] }, } ``` will return `{ \"allowed\": true }`, even though a specific user of the userset `group:finance#member` does not have the `reader` relationship with the given object. ### Requesting higher consistency By default, the Check API caches results for a short time to optimize performance. You may request higher consistency to inform the server that higher consistency should be preferred at the expense of increased latency. Care should be taken when requesting higher consistency due to the increased latency. ```json { \"tuple_key\": { \"user\": \"group:finance#member\", \"relation\": \"reader\", \"object\": \"document:2021-budget\" }, \"consistency\": \"HIGHER_CONSISTENCY\" } ``` * @summary Check whether a user is authorized to access an object * @param {string} storeId * @param {CheckRequest} body @@ -1256,7 +1258,7 @@ export class OpenFgaApi extends BaseAPI { } /** - * The ListObjects API returns a list of all the objects of the given type that the user has a relation with. To arrive at a result, the API uses: an authorization model, explicit tuples written through the Write API, contextual tuples present in the request, and implicit tuples that exist by virtue of applying set theory (such as `document:2021-budget#viewer@document:2021-budget#viewer`; the set of users who are viewers of `document:2021-budget` are the set of users who are the viewers of `document:2021-budget`). An `authorization_model_id` may be specified in the body. If it is not specified, the latest authorization model ID will be used. It is strongly recommended to specify authorization model id for better performance. You may also specify `contextual_tuples` that will be treated as regular tuples. Each of these tuples may have an associated `condition`. You may also provide a `context` object that will be used to evaluate the conditioned tuples in the system. It is strongly recommended to provide a value for all the input parameters of all the conditions, to ensure that all tuples be evaluated correctly. The response will contain the related objects in an array in the \"objects\" field of the response and they will be strings in the object format `:` (e.g. \"document:roadmap\"). The number of objects in the response array will be limited by the execution timeout specified in the flag OPENFGA_LIST_OBJECTS_DEADLINE and by the upper bound specified in the flag OPENFGA_LIST_OBJECTS_MAX_RESULTS, whichever is hit first. The objects given will not be sorted, and therefore two identical calls can give a given different set of objects. + * The ListObjects API returns a list of all the objects of the given type that the user has a relation with. To arrive at a result, the API uses: an authorization model, explicit tuples written through the Write API, contextual tuples present in the request, and implicit tuples that exist by virtue of applying set theory (such as `document:2021-budget#viewer@document:2021-budget#viewer`; the set of users who are viewers of `document:2021-budget` are the set of users who are the viewers of `document:2021-budget`). An `authorization_model_id` may be specified in the body. If it is not specified, the latest authorization model ID will be used. It is strongly recommended to specify authorization model id for better performance. You may also specify `contextual_tuples` that will be treated as regular tuples. Each of these tuples may have an associated `condition`. You may also provide a `context` object that will be used to evaluate the conditioned tuples in the system. It is strongly recommended to provide a value for all the input parameters of all the conditions, to ensure that all tuples be evaluated correctly. By default, the Check API caches results for a short time to optimize performance. You may specify a value of `HIGHER_CONSISTENCY` for the optional `consistency` parameter in the body to inform the server that higher conisistency is preferred at the expense of increased latency. Consideration should be given to the increased latency if requesting higher consistency. The response will contain the related objects in an array in the \"objects\" field of the response and they will be strings in the object format `:` (e.g. \"document:roadmap\"). The number of objects in the response array will be limited by the execution timeout specified in the flag OPENFGA_LIST_OBJECTS_DEADLINE and by the upper bound specified in the flag OPENFGA_LIST_OBJECTS_MAX_RESULTS, whichever is hit first. The objects given will not be sorted, and therefore two identical calls can give a given different set of objects. * @summary List all objects of the given type that the user has a relation with * @param {string} storeId * @param {ListObjectsRequest} body @@ -1282,7 +1284,7 @@ export class OpenFgaApi extends BaseAPI { } /** - * The ListUsers API returns a list of all the users of a specific type that have a relation to a given object. To arrive at a result, the API uses: an authorization model, explicit tuples written through the Write API, contextual tuples present in the request, and implicit tuples that exist by virtue of applying set theory (such as `document:2021-budget#viewer@document:2021-budget#viewer`; the set of users who are viewers of `document:2021-budget` are the set of users who are the viewers of `document:2021-budget`). An `authorization_model_id` may be specified in the body. If it is not specified, the latest authorization model ID will be used. It is strongly recommended to specify authorization model id for better performance. You may also specify `contextual_tuples` that will be treated as regular tuples. Each of these tuples may have an associated `condition`. You may also provide a `context` object that will be used to evaluate the conditioned tuples in the system. It is strongly recommended to provide a value for all the input parameters of all the conditions, to ensure that all tuples be evaluated correctly. The response will contain the related users in an array in the \"users\" field of the response. These results may include specific objects, usersets or type-bound public access. Each of these types of results is encoded in its own type and not represented as a string.In cases where a type-bound public acces result is returned (e.g. `user:*`), it cannot be inferred that all subjects of that type have a relation to the object; it is possible that negations exist and checks should still be queried on individual subjects to ensure access to that document.The number of users in the response array will be limited by the execution timeout specified in the flag OPENFGA_LIST_USERS_DEADLINE and by the upper bound specified in the flag OPENFGA_LIST_USERS_MAX_RESULTS, whichever is hit first. The returned users will not be sorted, and therefore two identical calls may yield different sets of users. + * The ListUsers API returns a list of all the users of a specific type that have a relation to a given object. To arrive at a result, the API uses: an authorization model, explicit tuples written through the Write API, contextual tuples present in the request, and implicit tuples that exist by virtue of applying set theory (such as `document:2021-budget#viewer@document:2021-budget#viewer`; the set of users who are viewers of `document:2021-budget` are the set of users who are the viewers of `document:2021-budget`). An `authorization_model_id` may be specified in the body. If it is not specified, the latest authorization model ID will be used. It is strongly recommended to specify authorization model id for better performance. You may also specify `contextual_tuples` that will be treated as regular tuples. Each of these tuples may have an associated `condition`. You may also provide a `context` object that will be used to evaluate the conditioned tuples in the system. It is strongly recommended to provide a value for all the input parameters of all the conditions, to ensure that all tuples be evaluated correctly. The response will contain the related users in an array in the \"users\" field of the response. These results may include specific objects, usersets or type-bound public access. Each of these types of results is encoded in its own type and not represented as a string.In cases where a type-bound public access result is returned (e.g. `user:*`), it cannot be inferred that all subjects of that type have a relation to the object; it is possible that negations exist and checks should still be queried on individual subjects to ensure access to that document.The number of users in the response array will be limited by the execution timeout specified in the flag OPENFGA_LIST_USERS_DEADLINE and by the upper bound specified in the flag OPENFGA_LIST_USERS_MAX_RESULTS, whichever is hit first. The returned users will not be sorted, and therefore two identical calls may yield different sets of users. * @summary List the users matching the provided filter who have a certain relation to a particular type. * @param {string} storeId * @param {ListUsersRequest} body @@ -1308,7 +1310,7 @@ export class OpenFgaApi extends BaseAPI { } /** - * The ReadAssertions API will return, for a given authorization model id, all the assertions stored for it. An assertion is an object that contains a tuple key, and the expectation of whether a call to the Check API of that tuple key will return true or false. + * The ReadAssertions API will return, for a given authorization model id, all the assertions stored for it. * @summary Read assertions for an authorization model ID * @param {string} storeId * @param {string} authorizationModelId @@ -1376,7 +1378,7 @@ export class OpenFgaApi extends BaseAPI { } /** - * The WriteAssertions API will upsert new assertions for an authorization model id, or overwrite the existing ones. An assertion is an object that contains a tuple key, and the expectation of whether a call to the Check API of that tuple key will return true or false. + * The WriteAssertions API will upsert new assertions for an authorization model id, or overwrite the existing ones. An assertion is an object that contains a tuple key, the expectation of whether a call to the Check API of that tuple key will return true or false, and optionally a list of contextual tuples. * @summary Upsert assertions for an authorization model ID * @param {string} storeId * @param {string} authorizationModelId diff --git a/apiModel.ts b/apiModel.ts index 92e0bc9..a39d323 100644 --- a/apiModel.ts +++ b/apiModel.ts @@ -65,6 +65,18 @@ export interface Assertion { * @memberof Assertion */ expectation: boolean; + /** + * + * @type {Array} + * @memberof Assertion + */ + contextual_tuples?: Array; + /** + * Additional request context that will be used to evaluate any ABAC conditions encountered in the query evaluation. + * @type {object} + * @memberof Assertion + */ + context?: object; } /** * @@ -91,6 +103,24 @@ export interface AssertionTupleKey { */ user: string; } +/** + * + * @export + * @enum {string} + */ + +export enum AuthErrorCode { + NoAuthError = 'no_auth_error', + AuthFailedInvalidSubject = 'auth_failed_invalid_subject', + AuthFailedInvalidAudience = 'auth_failed_invalid_audience', + AuthFailedInvalidIssuer = 'auth_failed_invalid_issuer', + InvalidClaims = 'invalid_claims', + AuthFailedInvalidBearerToken = 'auth_failed_invalid_bearer_token', + BearerTokenMissing = 'bearer_token_missing', + Unauthenticated = 'unauthenticated', + Forbidden = 'forbidden' +} + /** * * @export @@ -296,7 +326,7 @@ export interface ConditionParamTypeRef { /** - * - UNSPECIFIED: Default if not set. Behavior will be the same as MINIMIZE_LATENCY - MINIMIZE_LATENCY: Minimize latency at the potential expense of lower consistency. - HIGHER_CONSISTENCY: Prefer higher consistency, at the potential expense of increased latency. + * Controls the consistency preferences when calling the query APIs. - UNSPECIFIED: Default if not set. Behavior will be the same as MINIMIZE_LATENCY. - MINIMIZE_LATENCY: Minimize latency at the potential expense of lower consistency. - HIGHER_CONSISTENCY: Prefer higher consistency, at the potential expense of increased latency. * @export * @enum {string} */ @@ -437,7 +467,8 @@ export enum ErrorCode { InvalidContextualTuple = 'invalid_contextual_tuple', DuplicateContextualTuple = 'duplicate_contextual_tuple', InvalidAuthorizationModel = 'invalid_authorization_model', - UnsupportedSchemaVersion = 'unsupported_schema_version' + UnsupportedSchemaVersion = 'unsupported_schema_version', + Cancelled = 'cancelled' } /** @@ -518,6 +549,27 @@ export interface FgaObject { */ id: string; } +/** + * + * @export + * @interface ForbiddenResponse + */ +export interface ForbiddenResponse { + /** + * + * @type {AuthErrorCode} + * @memberof ForbiddenResponse + */ + code?: AuthErrorCode; + /** + * + * @type {string} + * @memberof ForbiddenResponse + */ + message?: string; +} + + /** * * @export @@ -564,7 +616,6 @@ export interface GetStoreResponse { export enum InternalErrorCode { NoInternalError = 'no_internal_error', InternalError = 'internal_error', - Cancelled = 'cancelled', DeadlineExceeded = 'deadline_exceeded', AlreadyExists = 'already_exists', ResourceExhausted = 'resource_exhausted', diff --git a/telemetry/attributes.ts b/telemetry/attributes.ts index 93b9c89..41ac4cd 100644 --- a/telemetry/attributes.ts +++ b/telemetry/attributes.ts @@ -111,4 +111,16 @@ export class TelemetryAttributes { return attributes; } + + static fromRequestBody(body: any, attributes: Record = {}): Record { + if (body?.authorization_model_id) { + attributes[TelemetryAttribute.FgaClientRequestModelId] = body.authorization_model_id; + } + + if (body?.tuple_key?.user) { + attributes[TelemetryAttribute.FgaClientUser] = body.tuple_key.user; + } + + return attributes; + } } diff --git a/tests/telemetry/attributes.test.ts b/tests/telemetry/attributes.test.ts index e1551bc..33bfee5 100644 --- a/tests/telemetry/attributes.test.ts +++ b/tests/telemetry/attributes.test.ts @@ -90,4 +90,20 @@ describe("TelemetryAttributes", () => { expect(result["fga-client.response.model_id"]).toEqual("model-id"); expect(result["http.server.request.duration"]).toEqual(10); }); + + test("should create attributes from a request body correctly", () => { + const body = { authorization_model_id: "model-id", tuple_key: { user: "user:anne" } }; + const attributes = TelemetryAttributes.fromRequestBody(body); + + expect(attributes[TelemetryAttribute.FgaClientRequestModelId]).toEqual("model-id"); + expect(attributes[TelemetryAttribute.FgaClientUser]).toEqual("user:anne"); + }); + + test("should create attributes from a request body without tuple_key", () => { + const body = { authorization_model_id: "model-id" }; + const attributes = TelemetryAttributes.fromRequestBody(body); + + expect(attributes[TelemetryAttribute.FgaClientRequestModelId]).toEqual("model-id"); + expect(attributes[TelemetryAttribute.FgaClientUser]).toBeUndefined(); + }); });