diff --git a/code_samples/authorization/get_decision.mdx b/code_samples/authorization/get_decision.mdx index 04276737..0475f6b3 100644 --- a/code_samples/authorization/get_decision.mdx +++ b/code_samples/authorization/get_decision.mdx @@ -34,19 +34,16 @@ func main() { // Get Decision using v2 API // Convenience constructors live in the authorization/v2 package: - // ForClientID, ForEmail, ForUserName, ForToken, WithRequestToken + // Entity: ForClientID, ForEmail, ForUserName, ForToken, WithRequestToken + // Resource: ForAttributeValues, ForRegisteredResourceValueFqn decisionReq := &authorization.GetDecisionRequest{ EntityIdentifier: authorization.ForClientID("opentdf"), Action: &policy.Action{ Name: "decrypt", }, - Resource: &authorization.Resource{ - Resource: &authorization.Resource_AttributeValues_{ - AttributeValues: &authorization.Resource_AttributeValues{ - Fqns: []string{"https://opentdf.io/attr/role/value/developer"}, - }, - }, - }, + Resource: authorization.ForAttributeValues( + "https://opentdf.io/attr/role/value/developer", + ), } decision, err := client.AuthorizationV2.GetDecision(context.Background(), decisionReq) @@ -141,7 +138,6 @@ import io.opentdf.platform.sdk.*; import java.util.concurrent.ExecutionException; import io.opentdf.platform.authorization.*; -import io.opentdf.platform.entity.*; import io.opentdf.platform.policy.*; public class GetDecision { @@ -158,28 +154,13 @@ public class GetDecision { // Get Decision using v2 API GetDecisionRequest request = GetDecisionRequest.newBuilder() - .setEntityIdentifier( - EntityIdentifier.newBuilder() - .setEntityChain( - EntityChain.newBuilder() - .addEntities( - Entity.newBuilder() - .setId("entity-1") - .setClientId("opentdf") - ) - ) - ) + .setEntityIdentifier(EntityIdentifiers.forClientId("opentdf")) .setAction( Action.newBuilder() .setName("decrypt") ) - .setResource( - Resource.newBuilder() - .setAttributeValues( - Resource.AttributeValues.newBuilder() - .addFqns("https://opentdf.io/attr/role/value/developer") - ) - ) + .setResource(Resources.forAttributeValues( + "https://opentdf.io/attr/role/value/developer")) .build(); GetDecisionResponse resp = sdk.getServices().authorization().getDecision(request).get(); @@ -202,6 +183,7 @@ public class GetDecision { import { Decision, } from "@opentdf/sdk/platform/authorization/v2/authorization_pb.js"; +import { EntityIdentifiers, Resources } from "@opentdf/sdk"; import { platformConnect, PlatformClient } from "@opentdf/sdk/platform"; async function main() { @@ -223,33 +205,11 @@ async function main() { // Get Decision using v2 API try { const response = await platformClient.v2.authorization.getDecision({ - entityIdentifier: { - identifier: { - case: "entityChain", - value: { - entities: [ - { - ephemeralId: "entity-1", - entityType: { - case: "clientId", - value: "opentdf", - }, - }, - ], - }, - }, - }, - action: { - name: "decrypt", - }, - resource: { - resource: { - case: "attributeValues", - value: { - fqns: ["https://opentdf.io/attr/role/value/developer"], - }, - }, - }, + entityIdentifier: EntityIdentifiers.forClientId("opentdf"), + action: { name: "decrypt" }, + resource: Resources.forAttributeValues( + "https://opentdf.io/attr/role/value/developer", + ), }); const decision = response.decision; diff --git a/docs/sdks/authorization.mdx b/docs/sdks/authorization.mdx index 72640fb5..0b600d36 100644 --- a/docs/sdks/authorization.mdx +++ b/docs/sdks/authorization.mdx @@ -37,8 +37,8 @@ func main() { log.Fatal(err) } - // All Go snippets below use `client` and `context.Background()`. - _, _ = client, context.Background() + // All Go snippets below use `client` and `ctx`. + ctx := context.Background() } ``` @@ -240,6 +240,140 @@ const response = await platform.v2.authorization.getDecision({ - **Claims** are used by the Entity Resolution Service (ERS) for custom claim-based entity resolution. - **Registered Resource** identifies an entity by a [registered resource](/components/policy/registered_resources) value FQN stored in platform policy, where the resource acts as a single entity for authorization decisions. +### Resource + +A `Resource` identifies the data being accessed in [GetDecision](#getdecision) and [GetDecisionBulk](#getdecisionbulk) calls. It can be specified as a set of attribute value FQNs (most common — e.g. the attributes on a TDF) or as a [registered resource](/components/policy/registered_resources) value FQN stored in platform policy. + + + + + + +| Helper | Description | +|--------|-------------| +| `authorizationv2.ForAttributeValues(fqns...)` | Resource from attribute value FQNs (e.g. those on a TDF) | +| `authorizationv2.ForRegisteredResourceValueFqn(fqn)` | Resource from a registered resource value FQN in policy | + +```go +import authorizationv2 "github.com/opentdf/platform/protocol/go/authorization/v2" + +req := &authorizationv2.GetDecisionRequest{ + Resource: authorizationv2.ForAttributeValues( + "https://example.com/attr/classification/value/confidential", + "https://example.com/attr/department/value/finance", + ), + // ... +} +``` + +
+Without helpers (manual proto construction) + +```go +&authorizationv2.Resource{ + Resource: &authorizationv2.Resource_AttributeValues_{ + AttributeValues: &authorizationv2.Resource_AttributeValues{ + Fqns: []string{ + "https://example.com/attr/classification/value/confidential", + "https://example.com/attr/department/value/finance", + }, + }, + }, +} +``` + +
+ +
+ + + + +| Helper | Description | +|--------|-------------| +| `Resources.forAttributeValues(String... fqns)` | Resource from attribute value FQNs (e.g. those on a TDF) | +| `Resources.forRegisteredResourceValueFqn(String fqn)` | Resource from a registered resource value FQN in policy | + +```java +import io.opentdf.platform.sdk.Resources; + +GetDecisionRequest request = GetDecisionRequest.newBuilder() + .setResource(Resources.forAttributeValues( + "https://example.com/attr/classification/value/confidential", + "https://example.com/attr/department/value/finance")) + // ... + .build(); +``` + +
+Without helpers (manual proto construction) + +```java +Resource.newBuilder() + .setAttributeValues( + Resource.AttributeValues.newBuilder() + .addFqns("https://example.com/attr/classification/value/confidential") + .addFqns("https://example.com/attr/department/value/finance")) + .build() +``` + +
+ +
+ + + + +| Helper | Description | +|--------|-------------| +| `Resources.forAttributeValues(...fqns)` | Resource from attribute value FQNs (e.g. those on a TDF) | +| `Resources.forRegisteredResourceValueFqn(fqn)` | Resource from a registered resource value FQN in policy | + +```typescript +import { Resources } from '@opentdf/sdk'; + +const response = await platform.v2.authorization.getDecision({ + resource: Resources.forAttributeValues( + 'https://example.com/attr/classification/value/confidential', + 'https://example.com/attr/department/value/finance', + ), + // ... +}); +``` + +
+Without helpers (manual object construction) + +```typescript +{ + resource: { + case: 'attributeValues', + value: { + fqns: [ + 'https://example.com/attr/classification/value/confidential', + 'https://example.com/attr/department/value/finance', + ], + }, + }, +} +``` + +
+ +
+
+ +**Resource variants:** + +| Variant | Go | Java | JavaScript | +|---------|-----|------|------------| +| Attribute values | `authorizationv2.ForAttributeValues(fqns...)` | `Resources.forAttributeValues(String... fqns)` | `Resources.forAttributeValues(...fqns)` | +| Registered resource | `authorizationv2.ForRegisteredResourceValueFqn(fqn)` | `Resources.forRegisteredResourceValueFqn(fqn)` | `Resources.forRegisteredResourceValueFqn(fqn)` | + +:::note +The helpers do not set `ephemeralId`. For [GetDecisionBulk](#getdecisionbulk) where you need to correlate requests with responses, set `ephemeralId` separately after construction (in Go, assign the field directly; in Java, use `.toBuilder().setEphemeralId(...).build()`) or use manual construction. +::: + --- ## GetEntitlements @@ -276,7 +410,7 @@ await platform.v2.authorization.getEntitlements({ ... }) | Parameter | Type | Required | Description | |-----------|------|----------|-------------| -| `entityIdentifier` | `EntityIdentifier` | Yes | The entity to query. Use [helpers](#entityidentifier) like `ForEmail(...)` (Go) or `EntityIdentifiers.forEmail(...)` (Java/JS). | +| `entityIdentifier` | [`EntityIdentifier`](#entityidentifier) | Yes | The entity to query. Use [helpers](#entityidentifier) like `ForEmail(...)` (Go) or `EntityIdentifiers.forEmail(...)` (Java/JS). | | `withComprehensiveHierarchy` | `bool` | No | When true, returns all entitled values for attributes with hierarchy rules, propagating down from the entitled value. | **Example** @@ -467,9 +601,9 @@ await platform.v2.authorization.getDecision({ ... }) | Parameter | Type | Required | Description | |-----------|------|----------|-------------| -| `entityIdentifier` | `EntityIdentifier` | Yes | The entity requesting access. Use [helpers](#entityidentifier) like `ForEmail(...)` (Go) or `EntityIdentifiers.forEmail(...)` (Java/JS). | +| `entityIdentifier` | [`EntityIdentifier`](#entityidentifier) | Yes | The entity requesting access. Use [helpers](#entityidentifier) like `ForEmail(...)` (Go) or `EntityIdentifiers.forEmail(...)` (Java/JS). | | `action` | `Action` | Yes | The action being performed (e.g., `decrypt`, `read`). | -| `resource` | `Resource` | Yes | The resource being accessed, identified by attribute value FQNs. | +| `resource` | [`Resource`](#resource) | Yes | The resource being accessed. Use [helpers](#resource) like `ForAttributeValues(...)` (Go) or `Resources.forAttributeValues(...)` (Java/JS). | **Example** @@ -487,16 +621,10 @@ decisionReq := &authorizationv2.GetDecisionRequest{ Action: &policy.Action{ Name: "decrypt", }, - Resource: &authorizationv2.Resource{ - Resource: &authorizationv2.Resource_AttributeValues_{ - AttributeValues: &authorizationv2.Resource_AttributeValues{ - Fqns: []string{ - "https://company.com/attr/clearance/value/confidential", - "https://company.com/attr/department/value/finance", - }, - }, - }, - }, + Resource: authorizationv2.ForAttributeValues( + "https://company.com/attr/clearance/value/confidential", + "https://company.com/attr/department/value/finance", + ), } decision, err := client.AuthorizationV2.GetDecision( @@ -529,13 +657,9 @@ import ( decisionReq := &authorizationv2.GetDecisionRequest{ EntityIdentifier: authorizationv2.ForToken(jwtToken), Action: &policy.Action{Name: "decrypt"}, - Resource: &authorizationv2.Resource{ - Resource: &authorizationv2.Resource_AttributeValues_{ - AttributeValues: &authorizationv2.Resource_AttributeValues{ - Fqns: []string{"https://company.com/attr/clearance/value/public"}, - }, - }, - }, + Resource: authorizationv2.ForAttributeValues( + "https://company.com/attr/clearance/value/public", + ), } decision, err := client.AuthorizationV2.GetDecision( @@ -604,6 +728,7 @@ for _, dr := range decisionResponse.GetDecisionResponses() { ```java import io.opentdf.platform.sdk.EntityIdentifiers; +import io.opentdf.platform.sdk.Resources; GetDecisionRequest request = GetDecisionRequest.newBuilder() .setEntityIdentifier(EntityIdentifiers.forEmail("user@company.com")) @@ -611,14 +736,9 @@ GetDecisionRequest request = GetDecisionRequest.newBuilder() Action.newBuilder() .setName("decrypt") ) - .setResource( - Resource.newBuilder() - .setAttributeValues( - Resource.AttributeValues.newBuilder() - .addFqns("https://company.com/attr/clearance/value/confidential") - .addFqns("https://company.com/attr/department/value/finance") - ) - ) + .setResource(Resources.forAttributeValues( + "https://company.com/attr/clearance/value/confidential", + "https://company.com/attr/department/value/finance")) .build(); GetDecisionResponse resp = sdk.getServices() @@ -641,23 +761,16 @@ if (decision.getDecision() == Decision.DECISION_PERMIT) { ```typescript -import { EntityIdentifiers } from '@opentdf/sdk'; +import { EntityIdentifiers, Resources } from '@opentdf/sdk'; import { Decision } from '@opentdf/sdk/platform/authorization/v2/authorization_pb.js'; const response = await platform.v2.authorization.getDecision({ entityIdentifier: EntityIdentifiers.forEmail('user@company.com'), action: { name: 'decrypt' }, - resource: { - resource: { - case: 'attributeValues', - value: { - fqns: [ - 'https://company.com/attr/clearance/value/confidential', - 'https://company.com/attr/department/value/finance', - ], - }, - }, - }, + resource: Resources.forAttributeValues( + 'https://company.com/attr/clearance/value/confidential', + 'https://company.com/attr/department/value/finance', + ), }); const decision = response.decision; @@ -720,9 +833,9 @@ Each `GetDecisionMultiResourceRequest` contains: | Field | Type | Required | Description | |-------|------|----------|-------------| -| `entityIdentifier` | `EntityIdentifier` | Yes | The entity requesting access. | +| `entityIdentifier` | [`EntityIdentifier`](#entityidentifier) | Yes | The entity requesting access. | | `action` | `Action` | Yes | The action being performed. | -| `resources` | `[]Resource` | Yes | Resources to evaluate, each with an `ephemeralId` for correlation. | +| `resources` | [`[]Resource`](#resource) | Yes | Resources to evaluate, each with an `ephemeralId` for correlation. | **Example** @@ -962,29 +1075,38 @@ Identifies the data being accessed. A resource can be specified in two ways: | `attributeValues.fqns` | `[]string` | Attribute value FQNs on the resource (1–20). Use this for TDF payloads or any resource identified by attribute values. | | `registeredResourceValueFqn` | `string` (URI) | A [registered resource](/components/policy/registered_resources) value FQN stored in platform policy. Alternative to `attributeValues`. | +Use the [Resource helpers](#resource) for concise construction: + + + + ```go -// Go -&authorizationv2.Resource{ - EphemeralId: "resource-1", - Resource: &authorizationv2.Resource_AttributeValues_{ - AttributeValues: &authorizationv2.Resource_AttributeValues{ - Fqns: []string{"https://example.com/attr/classification/value/secret"}, - }, - }, -} +// With helpers +authorizationv2.ForAttributeValues("https://example.com/attr/classification/value/secret") +authorizationv2.ForRegisteredResourceValueFqn("https://example.com/registered/value/my-resource") ``` + + + +```java +// With helpers +Resources.forAttributeValues("https://example.com/attr/classification/value/secret") +Resources.forRegisteredResourceValueFqn("https://example.com/registered/value/my-resource") +``` + + + + ```typescript -// JavaScript -{ - ephemeralId: 'resource-1', - resource: { - case: 'attributeValues', - value: { fqns: ['https://example.com/attr/classification/value/secret'] }, - }, -} +// With helpers +Resources.forAttributeValues('https://example.com/attr/classification/value/secret') +Resources.forRegisteredResourceValueFqn('https://example.com/registered/value/my-resource') ``` + + + ### EntityEntitlements Returned by [GetEntitlements](#getentitlements). One per entity, mapping attribute value FQNs to the actions that entity can perform. diff --git a/docs/sdks/discovery.mdx b/docs/sdks/discovery.mdx index f47ed8bd..faeb532e 100644 --- a/docs/sdks/discovery.mdx +++ b/docs/sdks/discovery.mdx @@ -39,8 +39,8 @@ func main() { log.Fatal(err) } - // All Go snippets below use `client` and `context.Background()`. - _, _ = client, context.Background() + // All Go snippets below use `client` and `ctx`. + ctx := context.Background() } ``` diff --git a/docs/sdks/tdf.mdx b/docs/sdks/tdf.mdx index 0364aa94..592be43e 100644 --- a/docs/sdks/tdf.mdx +++ b/docs/sdks/tdf.mdx @@ -25,7 +25,7 @@ This page covers the core TDF operations: - **[Decrypt Options](#decrypt-options)** — full option reference for `LoadTDF` - **[Assertions](#assertions)** — signed metadata: types, scopes, signing, and verification - **[Session Encryption](#session-encryption)** — provide your own RSA key for KAS response encryption -- **[Type Reference](#type-reference)** — `KASInfo`, `PolicyObject`, `Manifest`, `AssertionConfig` +- **[Type Reference](#type-reference)** — `TDFObject`, `KASInfo`, `PolicyObject`, `Manifest`, `AssertionConfig` - **[Experimental: Streaming Writer](#experimental-streaming-writer)** — segment-based API for large files and out-of-order assembly --- @@ -280,7 +280,7 @@ See [Encrypt Options](#encrypt-options) for the full list of configuration optio -`(*TDFObject, error)` — On success, a `TDFObject` with a `.Manifest()` method returning the [Manifest](#manifest-object) and a `.Size()` method returning the encrypted byte count. Returns a non-nil `error` on failure. +[`(*TDFObject, error)`](#tdfobject) — On success, a `TDFObject` with a `.Manifest()` method returning the [Manifest](#manifest-object) and a `.Size()` method returning the encrypted byte count. Returns a non-nil `error` on failure. @@ -1269,6 +1269,23 @@ See the [Encrypt Options](#encrypt-options) and [Decrypt Options](#decrypt-optio The following types are returned by or passed to the methods above. +### TDFObject + +**Go only.** Returned by [`CreateTDF`](#createtdf). Contains the manifest and size of the encrypted TDF. + +**Methods** + +| Method | Return type | Description | +|--------|-------------|-------------| +| `Manifest()` | [`Manifest`](#manifest-object) | The TDF manifest, including encryption info, key access objects, and assertions. | +| `Size()` | `int64` | Total byte count of the encrypted TDF written to the output. | + +:::note +Java's `CreateTDF` returns a [`Manifest`](#manifest-object) directly. JavaScript's returns a `DecoratedStream`. +::: + +--- + ### KASInfo `KASInfo` is the input type passed to `WithKasInformation` (Go) or used to build a `Config.KASInfo` (Java). It identifies a KAS endpoint and the key configuration to use when wrapping the data encryption key.