Discovery
Before encrypting data with CreateTDF, it helps to verify that the attributes you intend to use actually exist on the platform. Without this step, encryption succeeds but decryption fails later with a cryptic "resource not found" error because the attribute was never created.
The Go, Java, and JavaScript SDKs provide five methods to discover and validate attributes without manual platform queries.
Setup
All examples on this page assume you have created a platform client. See Authentication for full details including DPoP key binding.
- Go
- Java
- JavaScript
client, err := sdk.New("http://localhost:8080",
sdk.WithClientCredentials("opentdf", "secret", nil),
)
if err != nil {
log.Fatal(err)
}
// All Go snippets below use `client` and `context.Background()`.
SDK sdk = SDKBuilder.newBuilder()
.platformEndpoint("http://localhost:8080")
.clientSecret("opentdf", "secret")
.useInsecurePlaintextConnection(true)
.build();
// All Java snippets below use `sdk`.
import { authTokenInterceptor, clientCredentialsTokenProvider, OpenTDF } from '@opentdf/sdk';
const auth = { interceptors: [authTokenInterceptor(clientCredentialsTokenProvider({
clientId: 'opentdf', clientSecret: 'secret',
oidcOrigin: 'http://localhost:8080/auth/realms/opentdf',
}))] };
const platformUrl = 'http://localhost:8080';
// All JavaScript snippets below use `auth` and `platformUrl`.
// Standalone functions like listAttributes() take these as arguments.
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.
ListAttributes
Returns all active attributes on the platform. Use this to see what's available before choosing which attributes to apply to a TDF.
Signature
- Go
- Java
- JavaScript
client.ListAttributes(ctx, ...namespaceFilter)
sdk.listAttributes()
sdk.listAttributes(namespaceFilter)
await listAttributes(platformUrl, auth, namespaceFilter?)
Parameters
| Parameter | Type | Required | Description |
|---|---|---|---|
namespaceFilter | string | No | When provided, returns only attributes in this namespace (e.g., "opentdf.io"). |
Example
- Go
- Java
- JavaScript
attrs, err := client.ListAttributes(ctx)
if err != nil {
log.Fatalf("failed to list attributes: %v", err)
}
for _, a := range attrs {
fmt.Printf(" %s (%s)\n", a.GetFqn(), a.GetRule())
for _, v := range a.GetValues() {
fmt.Printf(" value: %s\n", v.GetValue())
}
}
To filter by namespace:
attrs, err := client.ListAttributes(ctx, "opentdf.io")
List<Attribute> attrs = sdk.listAttributes();
for (Attribute a : attrs) {
System.out.printf(" %s (%s)%n", a.getFqn(), a.getRule());
for (Value v : a.getValuesList()) {
System.out.printf(" value: %s%n", v.getValue());
}
}
To filter by namespace:
List<Attribute> attrs = sdk.listAttributes("opentdf.io");
import { listAttributes } from '@opentdf/sdk';
const attrs = await listAttributes(platformUrl, auth);
for (const a of attrs) {
console.log(a.fqn, a.rule);
for (const v of a.values) {
console.log(' value:', v.value);
}
}
To filter by namespace:
const attrs = await listAttributes(platformUrl, auth, 'opentdf.io');
Returns
A list of Attribute objects, each with nested values. Paginates automatically — you always get the full list back without managing page tokens.
AttributeExists
Reports whether an attribute definition exists on the platform. Returns true/false — useful for a quick existence check before adding values or constructing an access policy.
Signature
- Go
- Java
- JavaScript
client.AttributeExists(ctx, attributeFqn)
sdk.attributeExists(attributeFqn)
await attributeExists(platformUrl, auth, attributeFqn)
Parameters
| Parameter | Type | Required | Description |
|---|---|---|---|
attributeFqn | string | Yes | An attribute-level FQN (no /value/ segment): https://<namespace>/attr/<attribute_name> |
Example
- Go
- Java
- JavaScript
exists, err := client.AttributeExists(ctx, "https://opentdf.io/attr/department")
if err != nil {
log.Fatalf("service error: %v", err)
}
if !exists {
log.Println("attribute does not exist — create it before use")
}
boolean exists = sdk.attributeExists("https://opentdf.io/attr/department");
if (!exists) {
System.out.println("attribute does not exist — create it before use");
}
import { attributeExists } from '@opentdf/sdk';
const exists = await attributeExists(platformUrl, auth, 'https://opentdf.io/attr/department');
if (!exists) {
console.log('attribute does not exist — create it before use');
}
Returns
true if the attribute exists, false otherwise.
AttributeValueExists
Reports whether a specific attribute value FQN exists on the platform. Returns true/false — useful for spot-checking one pre-registered value.
Signature
- Go
- Java
- JavaScript
client.AttributeValueExists(ctx, valueFqn)
sdk.attributeValueExists(valueFqn)
await attributeValueExists(platformUrl, auth, valueFqn)
Parameters
| Parameter | Type | Required | Description |
|---|---|---|---|
valueFqn | string | Yes | A full attribute value FQN: https://<namespace>/attr/<attribute_name>/value/<value> |
Example
- Go
- Java
- JavaScript
exists, err := client.AttributeValueExists(ctx, "https://opentdf.io/attr/department/value/finance")
if err != nil {
log.Fatalf("service error: %v", err)
}
if !exists {
log.Println("value does not exist on this attribute")
}
boolean exists = sdk.attributeValueExists("https://opentdf.io/attr/department/value/finance");
if (!exists) {
System.out.println("value does not exist on this attribute");
}
import { attributeValueExists } from '@opentdf/sdk';
const exists = await attributeValueExists(platformUrl, auth, 'https://opentdf.io/attr/department/value/finance');
if (!exists) {
console.log('value does not exist on this attribute');
}
Returns
true if the value exists, false otherwise.
ValidateAttributes
Checks that a list of attribute value FQNs exist on the platform before calling CreateTDF. This catches misspellings and missing attributes at the point of use rather than at decryption time.
Signature
- Go
- Java
- JavaScript
client.ValidateAttributes(ctx, fqns...)
sdk.validateAttributes(fqns)
await validateAttributes(platformUrl, auth, fqns)
Parameters
| Parameter | Type | Required | Description |
|---|---|---|---|
fqns | list of strings | Yes | Attribute value FQNs to validate (up to 250 per call). |
Example
- Go
- Java
- JavaScript
fqns := []string{
"https://opentdf.io/attr/department/value/marketing",
"https://opentdf.io/attr/clearance/value/executive",
}
if err := client.ValidateAttributes(ctx, fqns...); err != nil {
log.Fatalf("attribute validation failed: %v", err)
// err will name the specific FQNs that are missing
}
// Safe to encrypt — all attributes confirmed present
_, err = client.CreateTDF(encryptedBuffer, dataReader,
sdk.WithDataAttributes(fqns...),
sdk.WithKasInformation(sdk.KASInfo{URL: platformEndpoint}),
)
List<String> fqns = List.of(
"https://opentdf.io/attr/department/value/marketing",
"https://opentdf.io/attr/clearance/value/executive"
);
try {
sdk.validateAttributes(fqns);
} catch (SDK.AttributeNotFoundException e) {
System.err.println("attribute validation failed: " + e.getMessage());
// getMessage() names the specific FQNs that are missing
}
// Safe to encrypt — all attributes confirmed present
Config.TDFConfig config = Config.newTDFConfig(
Config.withDataAttributes(fqns),
Config.withKasInformation(new Config.KASInfo(platformEndpoint, null))
);
sdk.createTDF(inputStream, outputStream, config);
import { validateAttributes, AttributeNotFoundError } from '@opentdf/sdk';
const fqns = [
'https://opentdf.io/attr/department/value/marketing',
'https://opentdf.io/attr/clearance/value/executive',
];
try {
await validateAttributes(platformUrl, auth, fqns);
} catch (e) {
if (e instanceof AttributeNotFoundError) {
console.error('attribute validation failed:', e.message);
// e.message names the specific FQNs that are missing
}
}
// Safe to encrypt — all attributes confirmed present
Returns
No return value on success. Throws/returns an error naming the specific FQNs that are missing.
Why this matters: CreateTDF succeeds even when the attribute doesn't exist on the platform — it embeds the FQN string in the TDF policy. The failure only surfaces later when a decryption client attempts to resolve the attribute through the KAS. ValidateAttributes makes that failure happen immediately, with a clear message.
Accepts up to 250 FQNs per call, matching the platform's limit. For larger sets, batch across multiple calls.
GetEntityAttributes
Returns the attribute value FQNs assigned to a specific entity (person or non-person). Use this to inspect what a user or service account has been granted — for example, to understand why someone can or cannot decrypt a TDF.
Signature
- Go
- Java
- JavaScript
client.GetEntityAttributes(ctx, entity)
sdk.getEntityAttributes(entity)
await platform.v2.authorization.getEntitlements({ ... })
The JS SDK does not expose a standalone getEntityAttributes function. Use getEntitlements via PlatformClient in a Node.js server environment.
Parameters
Go/Java:
| Parameter | Type | Required | Description |
|---|---|---|---|
entity | Entity | Yes | The entity to look up. Supports email, username, client ID, and UUID. |
JavaScript uses getEntitlements instead (see EntityIdentifier for the request shape).
Example
- Go
- Java
- JavaScript
import "github.com/opentdf/platform/protocol/go/authorization"
// By email address
entity := &authorization.Entity{
Id: "e1",
EntityType: &authorization.Entity_EmailAddress{EmailAddress: "alice@example.com"},
}
fqns, err := client.GetEntityAttributes(ctx, entity)
if err != nil {
log.Fatalf("failed to get entity attributes: %v", err)
}
fmt.Println("alice's entitlements:")
for _, fqn := range fqns {
fmt.Println(" ", fqn)
}
Other supported entity types:
// By username
&authorization.Entity{Id: "e1", EntityType: &authorization.Entity_UserName{UserName: "alice"}}
// By client ID (NPE / service account)
&authorization.Entity{Id: "e1", EntityType: &authorization.Entity_ClientId{ClientId: "my-service"}}
// By UUID
&authorization.Entity{Id: "e1", EntityType: &authorization.Entity_Uuid{Uuid: "550e8400-e29b-41d4-a716-446655440000"}}
import io.opentdf.platform.authorization.Entity;
// By email address
Entity entity = Entity.newBuilder()
.setId("e1")
.setEmailAddress("alice@example.com")
.build();
List<String> fqns = sdk.getEntityAttributes(entity);
System.out.println("alice's entitlements:");
for (String fqn : fqns) {
System.out.println(" " + fqn);
}
Other supported entity types:
// By username
Entity.newBuilder().setId("e1").setUserName("alice").build();
// By client ID (NPE / service account)
Entity.newBuilder().setId("e1").setClientId("my-service").build();
// By UUID
Entity.newBuilder().setId("e1").setUuid("550e8400-e29b-41d4-a716-446655440000").build();
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' },
},
],
},
},
},
});
if (resp.entitlements.length > 0) {
console.log("alice's entitlements:", resp.entitlements[0].actionsPerAttributeValueFqn);
}
Other supported entity types (placed inside the entities array):
// By username
{ ephemeralId: 'e1', entityType: { case: 'userName', value: 'alice' } }
// By client ID (NPE / service account)
{ ephemeralId: 'e1', entityType: { case: 'clientId', value: 'my-service' } }
Returns
Go/Java: A list of attribute value FQN strings that the entity is entitled to access. JavaScript: An EntityEntitlements response from getEntitlements, containing a map of FQNs to permitted actions.
Querying another entity's attributes requires your caller to have appropriate platform permissions on the GetEntitlements endpoint. Without this, the call will return a permission_denied error.
Typical Workflow
A common pattern is to validate attributes at application startup and surface helpful errors before any encryption happens:
- Go
- Java
- JavaScript
// 1. See what's available on the platform
attrs, err := client.ListAttributes(ctx)
if err != nil {
log.Fatalf("could not reach platform: %v", err)
}
log.Printf("platform has %d active attributes", len(attrs))
// 2. Check a specific attribute exists before using it
exists, err := client.AttributeExists(ctx, "https://opentdf.io/attr/department")
if err != nil {
log.Fatalf("service error: %v", err)
}
if !exists {
log.Fatalf("attribute missing — create it first")
}
// 3. Validate the specific values before encrypting
required := []string{
"https://opentdf.io/attr/department/value/marketing",
}
if err := client.ValidateAttributes(ctx, required...); err != nil {
log.Fatalf("required attributes missing: %v", err)
}
// 4. Encrypt with confidence
_, err = client.CreateTDF(encryptedBuffer, dataReader,
sdk.WithDataAttributes(required...),
sdk.WithKasInformation(sdk.KASInfo{URL: platformEndpoint}),
)
if err != nil {
log.Fatalf("encryption failed: %v", err)
}
log.Println("data encrypted successfully")
// 1. See what's available on the platform
List<Attribute> attrs = sdk.listAttributes();
System.out.printf("platform has %d active attributes%n", attrs.size());
// 2. Check a specific attribute exists before using it
if (!sdk.attributeExists("https://opentdf.io/attr/department")) {
System.err.println("attribute missing — create it first");
return;
}
// 3. Validate the specific values before encrypting
List<String> required = List.of("https://opentdf.io/attr/department/value/marketing");
try {
sdk.validateAttributes(required);
} catch (SDK.AttributeNotFoundException e) {
System.err.println("required attributes missing: " + e.getMessage());
return;
}
// 4. Encrypt with confidence
Config.TDFConfig config = Config.newTDFConfig(
Config.withDataAttributes(required),
Config.withKasInformation(new Config.KASInfo(platformEndpoint, null))
);
sdk.createTDF(inputStream, outputStream, config);
System.out.println("data encrypted successfully");
import { listAttributes, attributeExists, validateAttributes, AttributeNotFoundError, OpenTDF } from '@opentdf/sdk';
// 1. See what's available on the platform
const attrs = await listAttributes(platformUrl, auth);
console.log(`platform has ${attrs.length} active attributes`);
// 2. Check a specific attribute exists before using it
const exists = await attributeExists(platformUrl, auth, 'https://opentdf.io/attr/department');
if (!exists) {
console.error('attribute missing — create it first');
process.exit(1);
}
// 3. Validate the specific values before encrypting
const required = ['https://opentdf.io/attr/department/value/marketing'];
try {
await validateAttributes(platformUrl, auth, required);
} catch (e) {
if (e instanceof AttributeNotFoundError) {
console.error('required attributes missing:', e.message);
process.exit(1);
}
throw e;
}
// 4. Encrypt with confidence
const client = new OpenTDF({ ...auth, platformUrl });
const ciphertext = await client.createTDF({
source: { type: 'stream', location: dataStream },
attributes: required,
defaultKASEndpoint: platformUrl,
});
console.log('data encrypted successfully');
Related
- Managing Policy — create and manage attributes and namespaces
- Troubleshooting: Resource Not Found — common errors when attributes are missing
- Troubleshooting: Permission Denied — common errors when entities lack entitlements