Skip to main content

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.

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()`.
JavaScript examples use client credentials for simplicity

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

client.ListAttributes(ctx, ...namespaceFilter)

Parameters

ParameterTypeRequiredDescription
namespaceFilterstringNoWhen provided, returns only attributes in this namespace (e.g., "opentdf.io").

Example

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")

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

client.AttributeExists(ctx, attributeFqn)

Parameters

ParameterTypeRequiredDescription
attributeFqnstringYesAn attribute-level FQN (no /value/ segment): https://<namespace>/attr/<attribute_name>

Example

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")
}

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

client.AttributeValueExists(ctx, valueFqn)

Parameters

ParameterTypeRequiredDescription
valueFqnstringYesA full attribute value FQN: https://<namespace>/attr/<attribute_name>/value/<value>

Example

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")
}

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

client.ValidateAttributes(ctx, fqns...)

Parameters

ParameterTypeRequiredDescription
fqnslist of stringsYesAttribute value FQNs to validate (up to 250 per call).

Example

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}),
)

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.

tip

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

client.GetEntityAttributes(ctx, entity)

Parameters

Go/Java:

ParameterTypeRequiredDescription
entityEntityYesThe entity to look up. Supports email, username, client ID, and UUID.

JavaScript uses getEntitlements instead (see EntityIdentifier for the request shape).

Example

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"}}

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.

Authorization required

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:

// 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")