Overview
Some SDK functionality — including policy management and authorization decisions — is provided through a platform service client rather than through the core SDK. This page explains the difference and when you'll use each.
Core SDK vs. Platform Service Client
| Core SDK | Platform Service Client | |
|---|---|---|
| What it does | Wraps and unwraps TDF-protected data | Manages platform resources (policy, keys, authorization) |
| Calls platform | Some operations (e.g. key unwrap, service discovery) | Always — all methods are remote gRPC calls |
| Examples | CreateTdf, LoadTdf | GetNamespace, GetDecision, ListKeyAccessServers |
This is the same pattern used by cloud provider SDKs — you instantiate a typed client once (analogous to new S3Client() in AWS), then call methods on it to manage remote resources.
gRPC is a high-performance open-source remote procedure call framework. It uses HTTP/2 for transport and Protocol Buffers for serialization, enabling strongly-typed service contracts across languages.
Initializing the SDK client
The JavaScript SDK is designed for browser applications. The examples on this page use clientCredentialsTokenProvider because it's self-contained and easy to follow, but it requires a client secret and must not be used in browser code.
In production browser apps, complete an OIDC login flow to obtain a refresh token, then use refreshTokenProvider(). See the Authentication Decision Guide for help choosing the right method.
- Go
- Java
- JavaScript
import (
"github.com/opentdf/platform/sdk"
// Plus the service-specific package for each call, e.g.:
"github.com/opentdf/platform/protocol/go/policy/namespaces"
authorization "github.com/opentdf/platform/protocol/go/authorization/v2"
)
client, err := sdk.New("http://localhost:8080",
sdk.WithClientCredentials("client-id", "client-secret", nil),
)
if err != nil {
log.Fatal(err)
}
defer client.Close()
// Platform services are accessed directly on the client, e.g.:
resp, err := client.Namespaces.ListNamespaces(ctx, &namespaces.ListNamespacesRequest{})
decision, err := client.AuthorizationV2.GetDecision(ctx, &authorization.GetDecisionRequest{
// ...
})
import io.opentdf.platform.sdk.SDK;
import io.opentdf.platform.sdk.SDKBuilder;
SDK sdk = SDKBuilder.newBuilder()
.platformEndpoint("http://localhost:8080")
.clientSecret("client-id", "client-secret")
.useInsecurePlaintextConnection(true) // dev only — remove in production
.build();
import { authTokenInterceptor, clientCredentialsTokenProvider, OpenTDF } from '@opentdf/sdk';
import { PlatformClient } from '@opentdf/sdk/platform';
const auth = {
interceptors: [authTokenInterceptor(clientCredentialsTokenProvider({
clientId: 'client-id',
clientSecret: 'client-secret',
oidcOrigin: 'http://localhost:8080/auth/realms/opentdf',
}))],
};
const client = new OpenTDF({ ...auth, platformUrl: 'http://localhost:8080' });
const platform = new PlatformClient({ ...auth, platformUrl: 'http://localhost:8080' });
Response Objects
All platform API calls return protobuf response objects. The way you access fields differs by language: Go uses generated getter methods prefixed with Get, Java uses standard getters, and JavaScript uses direct property access with optional chaining.
GetAttributeValue — accessing a policy attribute value:
- Go
- Java
- JavaScript
resp, err := client.Attributes.GetAttributeValue(ctx, req)
v := resp.GetValue()
v.GetValue() // "confidential"
v.GetFqn() // "https://example.com/attr/classification/value/confidential"
v.GetId() // "a1b2c3d4-..."
var resp = sdk.getServices().attributes()
.getAttributeValueBlocking(req, Collections.emptyMap()).execute();
var v = resp.getValue();
v.getValue(); // "confidential"
v.getFqn(); // "https://example.com/attr/classification/value/confidential"
v.getId(); // "a1b2c3d4-..."
const resp = await platform.v1.attributes.getAttributeValue({ fqn: '...' });
resp.value?.value; // "confidential"
resp.value?.fqn; // "https://example.com/attr/classification/value/confidential"
resp.value?.id; // "a1b2c3d4-..."
ListAttributeValues — iterating over a list response:
- Go
- Java
- JavaScript
resp, err := client.Attributes.ListAttributeValues(ctx, req)
for _, v := range resp.GetValues() {
v.GetValue() // "confidential"
v.GetFqn() // "https://example.com/attr/classification/value/confidential"
}
var resp = sdk.getServices().attributes()
.listAttributeValuesBlocking(req, Collections.emptyMap()).execute();
for (var v : resp.getValuesList()) {
v.getValue(); // "confidential"
v.getFqn(); // "https://example.com/attr/classification/value/confidential"
}
const resp = await platform.v1.attributes.listAttributeValues({ attributeId: '...' });
for (const v of resp.values) {
v.value; // "confidential"
v.fqn; // "https://example.com/attr/classification/value/confidential"
}
GetDecision — accessing an authorization decision:
- Go
- Java
- JavaScript
resp, err := client.AuthorizationV2.GetDecision(ctx, req)
d := resp.GetDecision()
d.GetDecision() // DECISION_PERMIT or DECISION_DENY
d.GetRequiredObligations() // []string of obligation value FQNs
var resp = sdk.getServices().authorization().getDecision(req).get();
var d = resp.getDecision();
d.getDecision(); // DECISION_PERMIT or DECISION_DENY
d.getRequiredObligationsList(); // List<String> of obligation value FQNs
const resp = await platform.v2.authorization.getDecision({ ... });
resp.decision?.decision; // Decision.PERMIT or Decision.DENY
resp.decision?.requiredObligations; // string[] of obligation value FQNs
GetEntitlements — accessing entity entitlements:
- Go
- Java
- JavaScript
resp, err := client.AuthorizationV2.GetEntitlements(ctx, req)
for _, e := range resp.GetEntitlements() {
e.GetActionsPerAttributeValueFqn() // map of FQN → permitted actions
}
var resp = sdk.getServices().authorization().getEntitlements(req).get();
for (var e : resp.getEntitlementsList()) {
e.getActionsPerAttributeValueFqnMap(); // Map<String, Actions>
}
const resp = await platform.v2.authorization.getEntitlements({ ... });
for (const e of resp.entitlements) {
e.actionsPerAttributeValueFqn; // Record<string, Actions>
}
This pattern applies to all platform objects. Each SDK page includes type reference tables listing the available fields.