diff --git a/code_samples/authorization/get_decision.mdx b/code_samples/authorization/get_decision.mdx
index fb39b751..34328902 100644
--- a/code_samples/authorization/get_decision.mdx
+++ b/code_samples/authorization/get_decision.mdx
@@ -15,8 +15,7 @@ import (
"context"
"log"
- authorizationv2 "github.com/opentdf/platform/protocol/go/authorization/v2"
- "github.com/opentdf/platform/protocol/go/entity"
+ authorization "github.com/opentdf/platform/protocol/go/authorization/v2"
"github.com/opentdf/platform/protocol/go/policy"
"github.com/opentdf/platform/sdk"
)
@@ -34,27 +33,16 @@ func main() {
}
// Get Decision using v2 API
- decisionReq := &authorizationv2.GetDecisionRequest{
- EntityIdentifier: &authorizationv2.EntityIdentifier{
- Identifier: &authorizationv2.EntityIdentifier_EntityChain{
- EntityChain: &entity.EntityChain{
- Entities: []*entity.Entity{
- {
- EphemeralId: "entity-1",
- EntityType: &entity.Entity_ClientId{
- ClientId: "opentdf",
- },
- },
- },
- },
- },
- },
+ // Convenience constructors live in the authorization/v2 package:
+ // ForClientID, ForEmail, ForUserName, ForToken, WithRequestToken
+ decisionReq := &authorization.GetDecisionRequest{
+ EntityIdentifier: authorization.ForClientID("opentdf"),
Action: &policy.Action{
Name: "decrypt",
},
- Resource: &authorizationv2.Resource{
- Resource: &authorizationv2.Resource_AttributeValues_{
- AttributeValues: &authorizationv2.Resource_AttributeValues{
+ Resource: &authorization.Resource{
+ Resource: &authorization.Resource_AttributeValues_{
+ AttributeValues: &authorization.Resource_AttributeValues{
Fqns: []string{"https://opentdf.io/attr/role/value/developer"},
},
},
@@ -68,7 +56,7 @@ func main() {
decisionResult := decision.GetDecision()
log.Printf("Decision: %v", decisionResult.GetDecision())
- if decisionResult.GetDecision() == authorizationv2.Decision_DECISION_PERMIT {
+ if decisionResult.GetDecision() == authorization.Decision_DECISION_PERMIT {
log.Printf("✓ Access GRANTED")
if len(decisionResult.GetRequiredObligations()) > 0 {
log.Printf("Required obligations: %v", decisionResult.GetRequiredObligations())
diff --git a/code_samples/authorization/get_entitlements.mdx b/code_samples/authorization/get_entitlements.mdx
index e536918d..f03b9a82 100644
--- a/code_samples/authorization/get_entitlements.mdx
+++ b/code_samples/authorization/get_entitlements.mdx
@@ -13,8 +13,7 @@ import (
"context"
"log"
- "github.com/opentdf/platform/protocol/go/authorization"
- "github.com/opentdf/platform/protocol/go/entity"
+ authorization "github.com/opentdf/platform/protocol/go/authorization/v2"
"github.com/opentdf/platform/sdk"
)
@@ -33,22 +32,13 @@ func main() {
}
// Get Entitlements using v2 API
+ // Convenience constructors live in the authorization/v2 package:
+ // ForClientID, ForEmail, ForUserName, ForToken, WithRequestToken
entitlementReq := &authorization.GetEntitlementsRequest{
- EntityIdentifier: &authorization.EntityIdentifier{
- EntityChain: &entity.EntityChain{
- Entities: []*entity.Entity{
- {
- Id: "entity-1",
- EntityType: &entity.Entity_ClientId{
- ClientId: "opentdf",
- },
- },
- },
- },
- },
+ EntityIdentifier: authorization.ForClientID("opentdf"),
}
- entitlements, err := client.Authorization.GetEntitlements(context.Background(), entitlementReq)
+ entitlements, err := client.AuthorizationV2.GetEntitlements(context.Background(), entitlementReq)
if err != nil {
log.Fatal(err)
}
diff --git a/docs/sdks/authorization.mdx b/docs/sdks/authorization.mdx
index a59e6848..77580c55 100644
--- a/docs/sdks/authorization.mdx
+++ b/docs/sdks/authorization.mdx
@@ -143,41 +143,28 @@ Use `GetEntitlements` to discover what attribute values an entity can access. Th
```go
func getEntitlementsV2(client *sdk.SDK) {
- // Using v2 API with EntityIdentifier
entitlementReq := &authorizationv2.GetEntitlementsRequest{
- EntityIdentifier: &authorizationv2.EntityIdentifier{
- Identifier: &authorizationv2.EntityIdentifier_EntityChain{
- EntityChain: &entity.EntityChain{
- Entities: []*entity.Entity{
- {
- EphemeralId: "user-bob",
- EntityType: &entity.Entity_EmailAddress{
- EmailAddress: "bob@OrgA.com",
- },
- },
- },
- },
- },
- },
+ EntityIdentifier: authorizationv2.ForEmail("bob@OrgA.com"),
}
-
+
entitlements, err := client.AuthorizationV2.GetEntitlements(
- context.Background(),
+ context.Background(),
entitlementReq,
)
if err != nil {
log.Fatal(err)
}
-
+
// Process entitlements
for _, entitlement := range entitlements.GetEntitlements() {
- fmt.Printf("Entity has access to: %v\n",
+ fmt.Printf("Entity has access to: %v\n",
entitlement.GetActionsPerAttributeValueFqn())
}
}
```
-#### V1 API (Legacy)
+
+V1 API (Legacy)
```go
func getEntitlementsV1(client *sdk.SDK) {
@@ -202,27 +189,29 @@ func getEntitlementsV1(client *sdk.SDK) {
},
}},
}}
-
+
decisionRequest := &authorization.GetDecisionsRequest{
DecisionRequests: decisionRequests,
}
-
+
decisionResponse, err := client.Authorization.GetDecisions(
- context.Background(),
+ context.Background(),
decisionRequest,
)
if err != nil {
log.Fatal(err)
}
-
+
// Process decisions to understand entitlements
for _, dr := range decisionResponse.GetDecisionResponses() {
- fmt.Printf("Entity chain %s has decision: %v\n",
+ fmt.Printf("Entity chain %s has decision: %v\n",
dr.GetEntityChainId(), dr.GetDecision())
}
}
```
+
+
@@ -405,20 +394,7 @@ Use `GetDecision` when you need to authorize access to specific resources. This
```go
func getDecisionV2(client *sdk.SDK) {
decisionReq := &authorizationv2.GetDecisionRequest{
- EntityIdentifier: &authorizationv2.EntityIdentifier{
- Identifier: &authorizationv2.EntityIdentifier_EntityChain{
- EntityChain: &entity.EntityChain{
- Entities: []*entity.Entity{
- {
- EphemeralId: "user-123",
- EntityType: &entity.Entity_EmailAddress{
- EmailAddress: "user@company.com",
- },
- },
- },
- },
- },
- },
+ EntityIdentifier: authorizationv2.ForEmail("user@company.com"),
Action: &policy.Action{
Name: "decrypt",
},
@@ -433,15 +409,15 @@ func getDecisionV2(client *sdk.SDK) {
},
},
}
-
+
decision, err := client.AuthorizationV2.GetDecision(
- context.Background(),
+ context.Background(),
decisionReq,
)
if err != nil {
log.Fatal(err)
}
-
+
resDecision := decision.GetDecision()
if resDecision.GetDecision() == authorizationv2.Decision_DECISION_PERMIT {
fmt.Println("Access granted")
@@ -454,7 +430,8 @@ func getDecisionV2(client *sdk.SDK) {
}
```
-#### V1 API (Legacy)
+
+V1 API (Legacy)
```go
func getDecisionV1(client *sdk.SDK) {
@@ -479,19 +456,19 @@ func getDecisionV1(client *sdk.SDK) {
},
}},
}}
-
+
decisionRequest := &authorization.GetDecisionsRequest{
DecisionRequests: decisionRequests,
}
-
+
decisionResponse, err := client.Authorization.GetDecisions(
- context.Background(),
+ context.Background(),
decisionRequest,
)
if err != nil {
log.Fatal(err)
}
-
+
for _, dr := range decisionResponse.GetDecisionResponses() {
if dr.GetDecision() == authorization.DecisionResponse_DECISION_PERMIT {
fmt.Println("Access granted")
@@ -506,6 +483,8 @@ func getDecisionV1(client *sdk.SDK) {
}
```
+
+
@@ -624,20 +603,7 @@ func getBulkDecisionsV2(client *sdk.SDK) {
bulkReq := &authorizationv2.GetDecisionBulkRequest{
DecisionRequests: []*authorizationv2.GetDecisionMultiResourceRequest{
{
- EntityIdentifier: &authorizationv2.EntityIdentifier{
- Identifier: &authorizationv2.EntityIdentifier_EntityChain{
- EntityChain: &entity.EntityChain{
- Entities: []*entity.Entity{
- {
- EphemeralId: "user-123",
- EntityType: &entity.Entity_EmailAddress{
- EmailAddress: "user@company.com",
- },
- },
- },
- },
- },
- },
+ EntityIdentifier: authorizationv2.ForEmail("user@company.com"),
Action: &policy.Action{Name: "decrypt"},
Resources: []*authorizationv2.Resource{
{
@@ -683,7 +649,8 @@ func getBulkDecisionsV2(client *sdk.SDK) {
}
```
-#### V1 API (Legacy)
+
+V1 API (Legacy)
```go
func getBulkDecisionsV1(client *sdk.SDK) {
@@ -708,11 +675,11 @@ func getBulkDecisionsV1(client *sdk.SDK) {
},
},
}}
-
+
decisionRequest := &authorization.GetDecisionsRequest{
DecisionRequests: decisionRequests,
}
-
+
decisionResponse, err := client.Authorization.GetDecisions(
context.Background(),
decisionRequest,
@@ -720,7 +687,7 @@ func getBulkDecisionsV1(client *sdk.SDK) {
if err != nil {
log.Fatal(err)
}
-
+
for _, dr := range decisionResponse.GetDecisionResponses() {
fmt.Printf("Entity chain %s: %v\n",
dr.GetEntityChainId(),
@@ -732,6 +699,8 @@ func getBulkDecisionsV1(client *sdk.SDK) {
}
```
+
+
@@ -793,12 +762,15 @@ public void getBulkDecisions(SDK sdk) throws ExecutionException, InterruptedExce
}
```
-#### V1 API (Legacy)
+
+V1 API (Legacy)
import GetDecisionsExample from '@site/code_samples/java/get-decisions.mdx';
+
+
@@ -874,11 +846,34 @@ OpenTDF supports various entity types for flexible authentication:
- **ClientId**: Service-to-service authentication
- **EmailAddress**: User identification via email
-- **UserName**: User identification via username
+- **UserName**: User identification via username
- **UUID**: Direct entity UUID reference
- **Token**: JWT-based authentication
- **Claims**: Custom claims-based entities
+### Entity Identifier Helpers (Go)
+
+The Go SDK provides convenience constructors in the `authorization/v2` package that eliminate the deeply nested proto construction required to build an `EntityIdentifier`.
+
+| Helper | Description |
+|--------|-------------|
+| `authorizationv2.ForClientID(clientID string)` | Identifies a subject entity by client ID |
+| `authorizationv2.ForEmail(email string)` | Identifies a subject entity by email address |
+| `authorizationv2.ForUserName(username string)` | Identifies a subject entity by username |
+| `authorizationv2.ForToken(jwt string)` | Resolves the entity from the given JWT |
+| `authorizationv2.WithRequestToken()` | Derives the entity from the request's Authorization header |
+
+```go
+import authorization "github.com/opentdf/platform/protocol/go/authorization/v2"
+
+req := &authorization.GetDecisionRequest{
+ EntityIdentifier: authorization.ForClientID("opentdf"),
+ // ...
+}
+```
+
+All five constructors work with every v2 authorization method: `GetDecision`, `GetDecisionMultiResource`, `GetDecisionBulk`, and `GetEntitlements`.
+
### Token-Based Authentication Example
@@ -889,14 +884,7 @@ OpenTDF supports various entity types for flexible authentication:
```go
func getDecisionWithTokenV2(client *sdk.SDK, jwtToken string) {
decisionReq := &authorizationv2.GetDecisionRequest{
- EntityIdentifier: &authorizationv2.EntityIdentifier{
- Identifier: &authorizationv2.EntityIdentifier_Token{
- Token: &entity.Token{
- EphemeralId: "token-1",
- Jwt: jwtToken,
- },
- },
- },
+ EntityIdentifier: authorizationv2.ForToken(jwtToken),
Action: &policy.Action{Name: "decrypt"},
Resource: &authorizationv2.Resource{
Resource: &authorizationv2.Resource_AttributeValues_{
@@ -906,7 +894,7 @@ func getDecisionWithTokenV2(client *sdk.SDK, jwtToken string) {
},
},
}
-
+
decision, err := client.AuthorizationV2.GetDecision(
context.Background(),
decisionReq,
@@ -914,13 +902,14 @@ func getDecisionWithTokenV2(client *sdk.SDK, jwtToken string) {
if err != nil {
log.Fatal(err)
}
-
+
resDecision := decision.GetDecision()
fmt.Printf("Token-based decision: %v\n", resDecision.GetDecision())
}
```
-#### V1 API (Legacy)
+
+V1 API (Legacy)
```go
func getDecisionWithTokenV1(client *sdk.SDK, jwtToken string) {
@@ -943,11 +932,11 @@ func getDecisionWithTokenV1(client *sdk.SDK, jwtToken string) {
AttributeValueFqns: []string{"https://company.com/attr/clearance/value/public"},
}},
}}
-
+
decisionRequest := &authorization.GetDecisionsRequest{
DecisionRequests: decisionRequests,
}
-
+
decisionResponse, err := client.Authorization.GetDecisions(
context.Background(),
decisionRequest,
@@ -955,7 +944,7 @@ func getDecisionWithTokenV1(client *sdk.SDK, jwtToken string) {
if err != nil {
log.Fatal(err)
}
-
+
for _, dr := range decisionResponse.GetDecisionResponses() {
fmt.Printf("Token-based decision: %v\n", dr.GetDecision())
if len(dr.GetObligations()) > 0 {
@@ -965,6 +954,8 @@ func getDecisionWithTokenV1(client *sdk.SDK, jwtToken string) {
}
```
+
+
@@ -1048,7 +1039,7 @@ async function getDecisionWithToken(platformClient: PlatformClient, jwtToken: st
1. **Least Privilege**: Request only the minimum necessary permissions
2. **Token Validation**: Ensure JWT tokens are properly validated before use
-3. **Obligation Handling**: Always process and fulfill returned obligations
+3. **Obligation Handling**: Always process and fulfill returned [obligations](/sdks/policy#obligations)
4. **Error Handling**: Implement proper error handling and fallback policies
### Integration Patterns