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