From fbdd08f1e4795cf14afecacbc15565c956fa4f8d Mon Sep 17 00:00:00 2001 From: Mary Dickson Date: Fri, 10 Apr 2026 13:55:04 -0700 Subject: [PATCH 1/4] chore(docs): update Java/JS examples to use EntityIdentifier helpers All three SDKs now ship convenience constructors for EntityIdentifier (Go: ForEmail, Java: EntityIdentifiers.forEmail, JS: forEmail). Update the authorization and discovery docs to use these helpers instead of verbose nested proto/object construction. Co-Authored-By: Claude Opus 4.6 (1M context) --- docs/sdks/authorization.mdx | 177 +++++++++++++++--------------------- docs/sdks/discovery.mdx | 25 ++--- 2 files changed, 80 insertions(+), 122 deletions(-) diff --git a/docs/sdks/authorization.mdx b/docs/sdks/authorization.mdx index c97ddaef..d5ded973 100644 --- a/docs/sdks/authorization.mdx +++ b/docs/sdks/authorization.mdx @@ -88,7 +88,26 @@ req := &authorizationv2.GetDecisionRequest{ } ``` -**Java** — build the nested proto structure: +**Java** — use the `EntityIdentifiers` helper class: + +| Helper | Description | +|--------|-------------| +| `EntityIdentifiers.forEmail(email)` | Identify by email address | +| `EntityIdentifiers.forClientId(clientId)` | Identify by client ID (service account / NPE) | +| `EntityIdentifiers.forUserName(username)` | Identify by username | +| `EntityIdentifiers.forToken(jwt)` | Resolve entity from a JWT token | + +```java +import io.opentdf.platform.sdk.EntityIdentifiers; + +GetDecisionRequest request = GetDecisionRequest.newBuilder() + .setEntityIdentifier(EntityIdentifiers.forEmail("alice@example.com")) + // ... + .build(); +``` + +
+Without helpers (manual proto construction) ```java EntityIdentifier.newBuilder() @@ -103,7 +122,29 @@ EntityIdentifier.newBuilder() .build() ``` -**JavaScript** — use the `identifier` oneof: +
+ +**JavaScript** — use the named helper functions: + +| Helper | Description | +|--------|-------------| +| `forEmail(email)` | Identify by email address | +| `forClientId(clientId)` | Identify by client ID (service account / NPE) | +| `forUserName(username)` | Identify by username | +| `forToken(jwt)` | Resolve entity from a JWT token | +| `withRequestToken()` | Derive entity from the request's Authorization header | + +```typescript +import { forEmail } from '@opentdf/sdk'; + +const response = await platformClient.v2.authorization.getDecision({ + entityIdentifier: forEmail('alice@example.com'), + // ... +}); +``` + +
+Without helpers (manual object construction) ```typescript { @@ -126,19 +167,17 @@ EntityIdentifier.newBuilder() } ``` -**Supported entity types:** +
-| Type | Go helper | Java setter | JS `case` | -|------|-----------|-------------|-----------| -| Email | `ForEmail(email)` | `.setEmailAddress(email)` | `'emailAddress'` | -| Client ID | `ForClientID(id)` | `.setClientId(id)` | `'clientId'` | -| Username | `ForUserName(name)` | `.setUserName(name)` | `'userName'` | -| JWT Token | `ForToken(jwt)` | `.setToken(Token.newBuilder().setJwt(jwt))` | `'token'` | -| Claims | — | `.setClaims(claims)` | `'claims'` | -| Registered Resource | — | `.setRegisteredResourceValueFqn(fqn)` | `'registeredResourceValueFqn'` | +**Supported entity types:** -- **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. +| Type | Go | Java | JavaScript | +|------|-----|------|------------| +| Email | `ForEmail(email)` | `forEmail(email)` | `forEmail(email)` | +| Client ID | `ForClientID(id)` | `forClientId(id)` | `forClientId(id)` | +| Username | `ForUserName(name)` | `forUserName(name)` | `forUserName(name)` | +| JWT Token | `ForToken(jwt)` | `forToken(jwt)` | `forToken(jwt)` | +| Request Token | `WithRequestToken()` | — | `withRequestToken()` | --- @@ -176,7 +215,7 @@ await platformClient.v2.authorization.getEntitlements({ ... }) | Parameter | Type | Required | Description | |-----------|------|----------|-------------| -| `entityIdentifier` | `EntityIdentifier` | Yes | The entity to query. In Go, use helpers like `authorizationv2.ForEmail("user@example.com")`. | +| `entityIdentifier` | `EntityIdentifier` | Yes | The entity to query. Use [helpers](#entityidentifier) like `ForEmail(...)` (Go), `EntityIdentifiers.forEmail(...)` (Java), or `forEmail(...)` (JS). | | `withComprehensiveHierarchy` | `bool` | No | When true, returns all entitled values for attributes with hierarchy rules, propagating down from the entitled value. | **Example** @@ -279,18 +318,10 @@ for _, dr := range decisionResponse.GetDecisionResponses() { ```java +import io.opentdf.platform.sdk.EntityIdentifiers; + GetEntitlementsRequest request = GetEntitlementsRequest.newBuilder() - .setEntityIdentifier( - EntityIdentifier.newBuilder() - .setEntityChain( - EntityChain.newBuilder() - .addEntities( - Entity.newBuilder() - .setId("user-bob") - .setEmailAddress("bob@OrgA.com") - ) - ) - ) + .setEntityIdentifier(EntityIdentifiers.forEmail("bob@OrgA.com")) .build(); GetEntitlementsResponse resp = sdk.getServices() @@ -308,23 +339,10 @@ for (EntityEntitlements entitlement : resp.getEntitlementsList()) { ```typescript +import { forEmail } from '@opentdf/sdk'; + const response = await platformClient.v2.authorization.getEntitlements({ - entityIdentifier: { - identifier: { - case: 'entityChain', - value: { - entities: [ - { - ephemeralId: 'user-bob', - entityType: { - case: 'emailAddress', - value: 'bob@OrgA.com', - }, - }, - ], - }, - }, - }, + entityIdentifier: forEmail('bob@OrgA.com'), }); for (const entitlement of response.entitlements) { @@ -335,20 +353,10 @@ for (const entitlement of response.entitlements) { To expand hierarchy rules: ```typescript +import { forEmail } from '@opentdf/sdk'; + const response = await platformClient.v2.authorization.getEntitlements({ - entityIdentifier: { - identifier: { - case: 'entityChain', - value: { - entities: [ - { - ephemeralId: 'user-123', - entityType: { case: 'emailAddress', value: 'user@company.com' }, - }, - ], - }, - }, - }, + entityIdentifier: forEmail('user@company.com'), withComprehensiveHierarchy: true, }); @@ -398,7 +406,7 @@ await platformClient.v2.authorization.getDecision({ ... }) | Parameter | Type | Required | Description | |-----------|------|----------|-------------| -| `entityIdentifier` | `EntityIdentifier` | Yes | The entity requesting access. In Go, use helpers like `authorizationv2.ForEmail(...)` or `authorizationv2.ForToken(jwt)`. | +| `entityIdentifier` | `EntityIdentifier` | Yes | The entity requesting access. Use [helpers](#entityidentifier) like `ForEmail(...)` (Go), `EntityIdentifiers.forEmail(...)` (Java), or `forEmail(...)` (JS). | | `action` | `Action` | Yes | The action being performed (e.g., `decrypt`, `read`). | | `resource` | `Resource` | Yes | The resource being accessed, identified by attribute value FQNs. | @@ -534,18 +542,10 @@ for _, dr := range decisionResponse.GetDecisionResponses() { ```java +import io.opentdf.platform.sdk.EntityIdentifiers; + GetDecisionRequest request = GetDecisionRequest.newBuilder() - .setEntityIdentifier( - EntityIdentifier.newBuilder() - .setEntityChain( - EntityChain.newBuilder() - .addEntities( - Entity.newBuilder() - .setId("user-123") - .setEmailAddress("user@company.com") - ) - ) - ) + .setEntityIdentifier(EntityIdentifiers.forEmail("user@company.com")) .setAction( Action.newBuilder() .setName("decrypt") @@ -580,22 +580,11 @@ if (decision.getDecision() == Decision.DECISION_PERMIT) { ```typescript +import { forEmail } from '@opentdf/sdk'; import { Decision } from '@opentdf/sdk/platform/authorization/v2/authorization_pb.js'; const response = await platformClient.v2.authorization.getDecision({ - entityIdentifier: { - identifier: { - case: 'entityChain', - value: { - entities: [ - { - ephemeralId: 'user-123', - entityType: { case: 'emailAddress', value: 'user@company.com' }, - }, - ], - }, - }, - }, + entityIdentifier: forEmail('user@company.com'), action: { name: 'decrypt' }, resource: { resource: { @@ -778,20 +767,12 @@ for _, dr := range decisionResponse.GetDecisionResponses() { ```java +import io.opentdf.platform.sdk.EntityIdentifiers; + GetDecisionBulkRequest request = GetDecisionBulkRequest.newBuilder() .addDecisionRequests( GetDecisionMultiResourceRequest.newBuilder() - .setEntityIdentifier( - EntityIdentifier.newBuilder() - .setEntityChain( - EntityChain.newBuilder() - .addEntities( - Entity.newBuilder() - .setId("user-123") - .setEmailAddress("user@company.com") - ) - ) - ) + .setEntityIdentifier(EntityIdentifiers.forEmail("user@company.com")) .setAction(Action.newBuilder().setName("decrypt")) .addResources( Resource.newBuilder() @@ -841,22 +822,12 @@ import GetDecisionsExample from '@site/code_samples/java/get-decisions.mdx'; ```typescript +import { forEmail } from '@opentdf/sdk'; + const response = await platformClient.v2.authorization.getDecisionBulk({ decisionRequests: [ { - entityIdentifier: { - identifier: { - case: 'entityChain', - value: { - entities: [ - { - ephemeralId: 'user-123', - entityType: { case: 'emailAddress', value: 'user@company.com' }, - }, - ], - }, - }, - }, + entityIdentifier: forEmail('user@company.com'), action: { name: 'decrypt' }, resources: [ { diff --git a/docs/sdks/discovery.mdx b/docs/sdks/discovery.mdx index 04ba3ba3..fd0ca7b3 100644 --- a/docs/sdks/discovery.mdx +++ b/docs/sdks/discovery.mdx @@ -582,25 +582,13 @@ Entity.newBuilder().setId("e1").setUuid("550e8400-e29b-41d4-a716-446655440000"). ```typescript +import { forEmail } from '@opentdf/sdk'; import { PlatformClient } from '@opentdf/sdk/platform'; const platform = new PlatformClient({ ...auth, platformUrl }); const resp = await platform.v2.authorization.getEntitlements({ - entityIdentifier: { - identifier: { - case: 'entityChain', - value: { - ephemeralId: 'e1', - entities: [ - { - ephemeralId: 'e1', - entityType: { case: 'emailAddress', value: 'alice@example.com' }, - }, - ], - }, - }, - }, + entityIdentifier: forEmail('alice@example.com'), }); if (resp.entitlements.length > 0) { @@ -608,14 +596,13 @@ if (resp.entitlements.length > 0) { } ``` -Other supported entity types (placed inside the `entities` array): +Other supported [entity identifier helpers](/sdks/authorization#entityidentifier): ```typescript -// By username -{ ephemeralId: 'e1', entityType: { case: 'userName', value: 'alice' } } +import { forUserName, forClientId } from '@opentdf/sdk'; -// By client ID (NPE / service account) -{ ephemeralId: 'e1', entityType: { case: 'clientId', value: 'my-service' } } +forUserName('alice') // By username +forClientId('my-service') // By client ID (NPE / service account) ``` From 36068226dd015f2d1839ab1b6da2b2558f571ef4 Mon Sep 17 00:00:00 2001 From: Mary Dickson Date: Fri, 10 Apr 2026 13:59:45 -0700 Subject: [PATCH 2/4] chore(docs): wrap EntityIdentifier helpers in language tabs Co-Authored-By: Claude Opus 4.6 (1M context) --- docs/sdks/authorization.mdx | 12 +++++++++--- 1 file changed, 9 insertions(+), 3 deletions(-) diff --git a/docs/sdks/authorization.mdx b/docs/sdks/authorization.mdx index d5ded973..df126c28 100644 --- a/docs/sdks/authorization.mdx +++ b/docs/sdks/authorization.mdx @@ -69,7 +69,8 @@ const platformClient = new PlatformClient({ Every authorization call requires an `EntityIdentifier` — the entity (user, service, etc.) you're asking about. The entity can be identified by email, username, client ID, JWT token, claims, or registered resource FQN. -**Go** — use the v2 helper functions: + + | Helper | Description | |--------|-------------| @@ -88,7 +89,8 @@ req := &authorizationv2.GetDecisionRequest{ } ``` -**Java** — use the `EntityIdentifiers` helper class: + + | Helper | Description | |--------|-------------| @@ -124,7 +126,8 @@ EntityIdentifier.newBuilder() -**JavaScript** — use the named helper functions: + + | Helper | Description | |--------|-------------| @@ -169,6 +172,9 @@ const response = await platformClient.v2.authorization.getDecision({ + + + **Supported entity types:** | Type | Go | Java | JavaScript | From 6d3fac3becce32884a7ea2fad910770df13dcab8 Mon Sep 17 00:00:00 2001 From: Mary Dickson Date: Fri, 10 Apr 2026 14:10:22 -0700 Subject: [PATCH 3/4] chore(docs): use EntityIdentifiers namespace for JS examples Update JS examples to use `EntityIdentifiers.forEmail(...)` instead of bare `forEmail(...)` to match opentdf/web-sdk#916. Co-Authored-By: Claude Opus 4.6 (1M context) --- docs/sdks/authorization.mdx | 44 ++++++++++++++++++------------------- docs/sdks/discovery.mdx | 10 ++++----- 2 files changed, 27 insertions(+), 27 deletions(-) diff --git a/docs/sdks/authorization.mdx b/docs/sdks/authorization.mdx index df126c28..726fd68b 100644 --- a/docs/sdks/authorization.mdx +++ b/docs/sdks/authorization.mdx @@ -131,17 +131,17 @@ EntityIdentifier.newBuilder() | Helper | Description | |--------|-------------| -| `forEmail(email)` | Identify by email address | -| `forClientId(clientId)` | Identify by client ID (service account / NPE) | -| `forUserName(username)` | Identify by username | -| `forToken(jwt)` | Resolve entity from a JWT token | -| `withRequestToken()` | Derive entity from the request's Authorization header | +| `EntityIdentifiers.forEmail(email)` | Identify by email address | +| `EntityIdentifiers.forClientId(clientId)` | Identify by client ID (service account / NPE) | +| `EntityIdentifiers.forUserName(username)` | Identify by username | +| `EntityIdentifiers.forToken(jwt)` | Resolve entity from a JWT token | +| `EntityIdentifiers.withRequestToken()` | Derive entity from the request's Authorization header | ```typescript -import { forEmail } from '@opentdf/sdk'; +import { EntityIdentifiers } from '@opentdf/sdk'; const response = await platformClient.v2.authorization.getDecision({ - entityIdentifier: forEmail('alice@example.com'), + entityIdentifier: EntityIdentifiers.forEmail('alice@example.com'), // ... }); ``` @@ -179,11 +179,11 @@ const response = await platformClient.v2.authorization.getDecision({ | Type | Go | Java | JavaScript | |------|-----|------|------------| -| Email | `ForEmail(email)` | `forEmail(email)` | `forEmail(email)` | -| Client ID | `ForClientID(id)` | `forClientId(id)` | `forClientId(id)` | -| Username | `ForUserName(name)` | `forUserName(name)` | `forUserName(name)` | -| JWT Token | `ForToken(jwt)` | `forToken(jwt)` | `forToken(jwt)` | -| Request Token | `WithRequestToken()` | — | `withRequestToken()` | +| Email | `ForEmail(email)` | `EntityIdentifiers.forEmail(email)` | `EntityIdentifiers.forEmail(email)` | +| Client ID | `ForClientID(id)` | `forClientId(id)` | `EntityIdentifiers.forClientId(id)` | +| Username | `ForUserName(name)` | `forUserName(name)` | `EntityIdentifiers.forUserName(name)` | +| JWT Token | `ForToken(jwt)` | `forToken(jwt)` | `EntityIdentifiers.forToken(jwt)` | +| Request Token | `WithRequestToken()` | — | `EntityIdentifiers.withRequestToken()` | --- @@ -221,7 +221,7 @@ await platformClient.v2.authorization.getEntitlements({ ... }) | Parameter | Type | Required | Description | |-----------|------|----------|-------------| -| `entityIdentifier` | `EntityIdentifier` | Yes | The entity to query. Use [helpers](#entityidentifier) like `ForEmail(...)` (Go), `EntityIdentifiers.forEmail(...)` (Java), or `forEmail(...)` (JS). | +| `entityIdentifier` | `EntityIdentifier` | Yes | The entity to query. Use [helpers](#entityidentifier) like `ForEmail(...)` (Go), `EntityIdentifiers.forEmail(...)` (Java), or `EntityIdentifiers.forEmail(...)` (JS). | | `withComprehensiveHierarchy` | `bool` | No | When true, returns all entitled values for attributes with hierarchy rules, propagating down from the entitled value. | **Example** @@ -345,10 +345,10 @@ for (EntityEntitlements entitlement : resp.getEntitlementsList()) { ```typescript -import { forEmail } from '@opentdf/sdk'; +import { EntityIdentifiers } from '@opentdf/sdk'; const response = await platformClient.v2.authorization.getEntitlements({ - entityIdentifier: forEmail('bob@OrgA.com'), + entityIdentifier: EntityIdentifiers.forEmail('bob@OrgA.com'), }); for (const entitlement of response.entitlements) { @@ -359,10 +359,10 @@ for (const entitlement of response.entitlements) { To expand hierarchy rules: ```typescript -import { forEmail } from '@opentdf/sdk'; +import { EntityIdentifiers } from '@opentdf/sdk'; const response = await platformClient.v2.authorization.getEntitlements({ - entityIdentifier: forEmail('user@company.com'), + entityIdentifier: EntityIdentifiers.forEmail('user@company.com'), withComprehensiveHierarchy: true, }); @@ -412,7 +412,7 @@ await platformClient.v2.authorization.getDecision({ ... }) | Parameter | Type | Required | Description | |-----------|------|----------|-------------| -| `entityIdentifier` | `EntityIdentifier` | Yes | The entity requesting access. Use [helpers](#entityidentifier) like `ForEmail(...)` (Go), `EntityIdentifiers.forEmail(...)` (Java), or `forEmail(...)` (JS). | +| `entityIdentifier` | `EntityIdentifier` | Yes | The entity requesting access. Use [helpers](#entityidentifier) like `ForEmail(...)` (Go), `EntityIdentifiers.forEmail(...)` (Java), or `EntityIdentifiers.forEmail(...)` (JS). | | `action` | `Action` | Yes | The action being performed (e.g., `decrypt`, `read`). | | `resource` | `Resource` | Yes | The resource being accessed, identified by attribute value FQNs. | @@ -586,11 +586,11 @@ if (decision.getDecision() == Decision.DECISION_PERMIT) { ```typescript -import { forEmail } from '@opentdf/sdk'; +import { EntityIdentifiers } from '@opentdf/sdk'; import { Decision } from '@opentdf/sdk/platform/authorization/v2/authorization_pb.js'; const response = await platformClient.v2.authorization.getDecision({ - entityIdentifier: forEmail('user@company.com'), + entityIdentifier: EntityIdentifiers.forEmail('user@company.com'), action: { name: 'decrypt' }, resource: { resource: { @@ -828,12 +828,12 @@ import GetDecisionsExample from '@site/code_samples/java/get-decisions.mdx'; ```typescript -import { forEmail } from '@opentdf/sdk'; +import { EntityIdentifiers } from '@opentdf/sdk'; const response = await platformClient.v2.authorization.getDecisionBulk({ decisionRequests: [ { - entityIdentifier: forEmail('user@company.com'), + entityIdentifier: EntityIdentifiers.forEmail('user@company.com'), action: { name: 'decrypt' }, resources: [ { diff --git a/docs/sdks/discovery.mdx b/docs/sdks/discovery.mdx index fd0ca7b3..a286729f 100644 --- a/docs/sdks/discovery.mdx +++ b/docs/sdks/discovery.mdx @@ -582,13 +582,13 @@ Entity.newBuilder().setId("e1").setUuid("550e8400-e29b-41d4-a716-446655440000"). ```typescript -import { forEmail } from '@opentdf/sdk'; +import { EntityIdentifiers } from '@opentdf/sdk'; import { PlatformClient } from '@opentdf/sdk/platform'; const platform = new PlatformClient({ ...auth, platformUrl }); const resp = await platform.v2.authorization.getEntitlements({ - entityIdentifier: forEmail('alice@example.com'), + entityIdentifier: EntityIdentifiers.forEmail('alice@example.com'), }); if (resp.entitlements.length > 0) { @@ -599,10 +599,10 @@ if (resp.entitlements.length > 0) { Other supported [entity identifier helpers](/sdks/authorization#entityidentifier): ```typescript -import { forUserName, forClientId } from '@opentdf/sdk'; +import { EntityIdentifiers } from '@opentdf/sdk'; -forUserName('alice') // By username -forClientId('my-service') // By client ID (NPE / service account) +EntityIdentifiers.forUserName('alice') // By username +EntityIdentifiers.forClientId('my-service') // By client ID (NPE / service account) ``` From e921be4a9ef9ef729297eb8a1e2e49fdaaa558ee Mon Sep 17 00:00:00 2001 From: Mary Dickson Date: Fri, 10 Apr 2026 14:32:57 -0700 Subject: [PATCH 4/4] chore(docs): restore Claims/Registered Resource types, fix Java prefix Address Gemini review feedback: - Restore Claims and Registered Resource rows to entity types table - Add EntityIdentifiers. prefix to Java column for consistency Co-Authored-By: Claude Opus 4.6 (1M context) --- docs/sdks/authorization.mdx | 11 ++++++++--- 1 file changed, 8 insertions(+), 3 deletions(-) diff --git a/docs/sdks/authorization.mdx b/docs/sdks/authorization.mdx index 726fd68b..da56c633 100644 --- a/docs/sdks/authorization.mdx +++ b/docs/sdks/authorization.mdx @@ -180,10 +180,15 @@ const response = await platformClient.v2.authorization.getDecision({ | Type | Go | Java | JavaScript | |------|-----|------|------------| | Email | `ForEmail(email)` | `EntityIdentifiers.forEmail(email)` | `EntityIdentifiers.forEmail(email)` | -| Client ID | `ForClientID(id)` | `forClientId(id)` | `EntityIdentifiers.forClientId(id)` | -| Username | `ForUserName(name)` | `forUserName(name)` | `EntityIdentifiers.forUserName(name)` | -| JWT Token | `ForToken(jwt)` | `forToken(jwt)` | `EntityIdentifiers.forToken(jwt)` | +| Client ID | `ForClientID(id)` | `EntityIdentifiers.forClientId(id)` | `EntityIdentifiers.forClientId(id)` | +| Username | `ForUserName(name)` | `EntityIdentifiers.forUserName(name)` | `EntityIdentifiers.forUserName(name)` | +| JWT Token | `ForToken(jwt)` | `EntityIdentifiers.forToken(jwt)` | `EntityIdentifiers.forToken(jwt)` | | Request Token | `WithRequestToken()` | — | `EntityIdentifiers.withRequestToken()` | +| Claims | — | manual proto construction | manual object construction | +| Registered Resource | — | manual proto construction | manual object construction | + +- **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. ---