Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
18 commits
Select commit Hold shift + click to select a range
d53b54b
Improve authorization SDK documentation and fix API version inconsist…
jp-ayyappan Aug 11, 2025
180d3e5
Address review comments: fix missing imports and undefined variable
jp-ayyappan Aug 11, 2025
b6ce8fe
Update getEntitlements examples to use realistic email-based user
jp-ayyappan Aug 11, 2025
88ac723
Address all remaining review comments: improve code quality and consi…
jp-ayyappan Aug 11, 2025
9315721
Standardize platform endpoints across all code samples to http://loca…
jp-ayyappan Aug 11, 2025
24e969e
Address PR review feedback from Gemini Code Assist
jp-ayyappan Aug 11, 2025
50b74e1
Fix protobuf getter usage in Token-based authentication example
jp-ayyappan Aug 12, 2025
8257d8b
Add obligation handling to authorization examples
jp-ayyappan Aug 12, 2025
33ea993
Fix OpenTDF Authorization SDK documentation with accurate v1/v2 API e…
jp-ayyappan Aug 15, 2025
b17b219
fix(docs): Fix authorization SDK examples for API consistency
jp-ayyappan Aug 15, 2025
5e28100
fix(docs): Add missing Entity_CategorySchema import in JavaScript exa…
jp-ayyappan Aug 15, 2025
75b6cc2
Update code_samples/authorization/get_decision.mdx
jp-ayyappan Aug 19, 2025
c518f86
Updated ts code
jp-ayyappan Aug 22, 2025
ea4e4cf
Merge remote-tracking branch 'origin/main' into docs/improve-authoriz…
jp-ayyappan Aug 22, 2025
9cef662
Update architecture documentation
jp-ayyappan Aug 23, 2025
b8a2227
docs(architecture): revise diagram to focus on OpenTDF components
jp-ayyappan Aug 25, 2025
057617d
feat(docs): overhaul architecture page for clarity and usability
jp-ayyappan Aug 25, 2025
073283b
Merge branch 'main' into docs/improve-authorization-sdk-documentation
jp-ayyappan Aug 25, 2025
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 3 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -38,3 +38,6 @@ node_modules
.github/vale-styles/*
# Except for the config directory where we keep the vocab
!.github/vale-styles/config/

# Ignore manual test scripts
manual_tests/
262 changes: 211 additions & 51 deletions code_samples/authorization/get_decision.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -6,73 +6,138 @@ import TabItem from '@theme/TabItem';
<Tabs>
<TabItem value="go" label="Go">

#### V2 API (Recommended)

```go
package main

import (
"context"
"log"

"github.com/opentdf/platform/protocol/go/authorization"
authorizationv2 "github.com/opentdf/platform/protocol/go/authorization/v2"
"github.com/opentdf/platform/protocol/go/entity"
"github.com/opentdf/platform/protocol/go/policy"
"github.com/opentdf/platform/sdk"
)

func main() {

platformEndpoint := "http://localhost:9002"
platformEndpoint := "http://localhost:8080"

// Create a new client
client, err := sdk.New(
platformEndpoint,
sdk.WithClientCredentials("opentdf", "secret", nil),
)

if err != nil {
log.Fatal(err)
}

// Get Entitlements

decision := &authorization.GetDecisionsRequest{
DecisionRequests: []*authorization.DecisionRequest{
{
Actions: []*policy.Action{
{
Value: &policy.Action_Standard{
Standard: policy.Action_STANDARD_ACTION_DECRYPT,
},
},
},
EntityChains: []*authorization.EntityChain{
{
Id: "entity-chain-1",
Entities: []*authorization.Entity{
{
Id: "entity-1",
EntityType: &authorization.Entity_ClientId{
ClientId: "opentdf",
},
// 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",
},
},
},
},
},
ResourceAttributes: []*authorization.ResourceAttribute{
{
ResourceAttributesId: "resource-attribute-1",
AttributeValueFqns: []string{"https://opentdf.io/attr/role/value/developer"},
},
},
},
Action: &policy.Action{
Name: "decrypt",
},
Resource: &authorizationv2.Resource{
Resource: &authorizationv2.Resource_AttributeValues_{
AttributeValues: &authorizationv2.Resource_AttributeValues{
Fqns: []string{"https://opentdf.io/attr/role/value/developer"},
},
},
},
}

decisions, err := client.Authorization.GetDecisions(context.Background(), decision)
decision, err := client.AuthorizationV2.GetDecision(context.Background(), decisionReq)
if err != nil {
log.Fatal(err)
}

decisionResult := decision.GetDecision()
log.Printf("Decision: %v", decisionResult.GetDecision())
if decisionResult.GetDecision() == authorizationv2.Decision_DECISION_PERMIT {
log.Printf("βœ“ Access GRANTED")
// Note: ResourceDecision doesn't have obligations in v2 API
}
}
```

#### V1 API (Legacy)

```go
package main

import (
"context"
"log"

"github.com/opentdf/platform/protocol/go/authorization"
"github.com/opentdf/platform/protocol/go/policy"
"github.com/opentdf/platform/sdk"
)

func main() {
platformEndpoint := "http://localhost:8080"

// Create a new client
client, err := sdk.New(
platformEndpoint,
sdk.WithClientCredentials("opentdf", "secret", nil),
)
if err != nil {
log.Fatal(err)
}

// Get Decision using v1 API (bulk decisions)
decisionRequests := []*authorization.DecisionRequest{{
Actions: []*policy.Action{{
Name: "decrypt",
}},
EntityChains: []*authorization.EntityChain{{
Id: "ec1",
Entities: []*authorization.Entity{{
EntityType: &authorization.Entity_ClientId{
ClientId: "opentdf",
},
Category: authorization.Entity_CATEGORY_SUBJECT,
}},
}},
ResourceAttributes: []*authorization.ResourceAttribute{{
AttributeValueFqns: []string{"https://opentdf.io/attr/role/value/developer"},
}},
}}

decisionRequest := &authorization.GetDecisionsRequest{
DecisionRequests: decisionRequests,
}

decisionResponse, err := client.Authorization.GetDecisions(context.Background(), decisionRequest)
if err != nil {
log.Fatal(err)
}

log.Printf("Decisions: %v", decisions.GetDecisionResponses())
for _, dr := range decisionResponse.GetDecisionResponses() {
log.Printf("Decision for entity chain %s: %v", dr.GetEntityChainId(), dr.GetDecision())
if dr.GetDecision() == authorization.DecisionResponse_DECISION_PERMIT {
log.Printf("βœ“ Access GRANTED")
if len(dr.GetObligations()) > 0 {
log.Printf("Obligations: %v", dr.GetObligations())
}
}
}
}
```

Expand All @@ -86,43 +151,138 @@ import io.opentdf.platform.sdk.*;
import java.util.concurrent.ExecutionException;

import io.opentdf.platform.authorization.*;
import io.opentdf.platform.policy.Action;
import io.opentdf.platform.entity.*;
import io.opentdf.platform.policy.*;

import java.util.List;

public class GetDecisions {
public class GetDecision {
public static void main(String[] args) throws ExecutionException, InterruptedException{

String clientId = "opentdf";
String clientSecret = "secret";
String platformEndpoint = "localhost:8080";
String platformEndpoint = "http://localhost:8080";

SDKBuilder builder = new SDKBuilder();
SDK sdk = builder.platformEndpoint(platformEndpoint)
.clientSecret(clientId, clientSecret).useInsecurePlaintextConnection(true)
.build();

GetDecisionsRequest request = GetDecisionsRequest.newBuilder()
.addDecisionRequests(DecisionRequest.newBuilder()
.addEntityChains(EntityChain.newBuilder().setId("ec1").addEntities(Entity.newBuilder().setId("entity-1").setClientId("opentdf")))
.addActions(Action.newBuilder().setStandard(Action.StandardAction.STANDARD_ACTION_DECRYPT))
.addResourceAttributes(ResourceAttribute.newBuilder().setResourceAttributesId("resource-attribute-1")
.addAttributeValueFqns("https://mynamespace.com/attr/test/value/test1"))
).build();

GetDecisionsResponse resp = sdk.getServices().authorization().getDecisions(request).get();
// Get Decision using v2 API
GetDecisionRequest request = GetDecisionRequest.newBuilder()
.setEntityIdentifier(
EntityIdentifier.newBuilder()
.setEntityChain(
EntityChain.newBuilder()
.addEntities(
Entity.newBuilder()
.setId("entity-1")
.setClientId("opentdf")
)
)
)
.setAction(
Action.newBuilder()
.setName("decrypt")
)
.setResource(
Resource.newBuilder()
.setAttributeValues(
Resource.AttributeValues.newBuilder()
.addFqns("https://opentdf.io/attr/role/value/developer")
)
)
.build();

List<DecisionResponse> decisions = resp.getDecisionResponsesList();
GetDecisionResponse resp = sdk.getServices().authorization().getDecision(request).get();

System.out.println(DecisionResponse.Decision.forNumber(decisions.get(0).getDecisionValue()));
Decision decision = resp.getDecision();
System.out.println("Decision: " + decision.getDecision());
if (decision.getDecision() == Decision.DECISION_PERMIT && decision.getObligationsCount() > 0) {
System.out.println("Obligations: " + decision.getObligationsList());
}
}
}
```

</TabItem>
<TabItem value="js" label="Javascript">
<TabItem value="js" label="TypeScript">

```typescript
import {
DecisionResponse_Decision,
Entity_Category,
type GetDecisionsResponse,
} from "@opentdf/sdk/platform/authorization/authorization_pb.js";
import { platformConnect, PlatformClient } from "@opentdf/sdk/platform";

async function main() {
const platformUrl = "http://localhost:8080";

// Assume you have an existing access token
const accessToken = "your-refresh-token-here";

const interceptor: platformConnect.Interceptor = (next) => async (req) => {
req.header.set("Authorization", `Bearer ${accessToken}`);
return next(req);
};

const platformClient = new PlatformClient({
platformUrl: platformUrl,
interceptors: [interceptor],
});

// Get Decision using v1 API (bulk decisions)

try {
const response = (await platformClient.v1.authorization.getDecisions({
decisionRequests: [
{
entityChains: [
{
id: "ec1",
entities: [
{
id: "entity-1",
entityType: {
case: "clientId",
value: "opentdf",
},
category: Entity_Category.SUBJECT,
},
],
},
],
actions: [
{
name: "decrypt",
},
],
resourceAttributes: [
{
resourceAttributesId: "resource-1",
attributeValueFqns: [
"https://opentdf.io/attr/role/value/developer",
],
},
],
},
],
})) as GetDecisionsResponse;

response.decisionResponses.forEach((decision) => {
console.log("Decision:", decision.decision);
if (
decision.decision === DecisionResponse_Decision.PERMIT &&
decision.obligations?.length > 0
) {
console.log("Obligations:", decision.obligations);
}
});
} catch (error) {
console.error("Error:", error);
}
}

```javascript
main();
```

</TabItem>
Expand Down
Loading