Skip to main content

Managing Policy

Policy is the set of rules that govern who can access data and under what conditions. It is made up of namespaces, attributes, subject mappings, and subject condition sets. See Policy for the concept overview. The SDK provides CRUD access to these policy rules through remote gRPC calls powered by the platform service client.

Setup

All examples on this page assume you have created a platform client. See Authentication for full details including DPoP key binding.

package main

import (
"context"
"log"

"github.com/opentdf/platform/sdk"
)

func main() {
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.

Metadata

All policy objects support optional metadata. When creating or updating a resource, you can pass a metadata object containing labels — a flat map of string key-value pairs:

{
"labels": {
"owner": "platform-team",
"env": "production"
}
}

labels is the only supported field. Other fields are silently ignored. When updating, use metadataUpdateBehavior to control whether labels are replaced or merged (see Update a Namespace for an example).

Pagination

All List operations return a pagination object alongside the results:

FieldTypeDescription
currentOffsetintThe offset that was requested.
nextOffsetintThe offset to use for the next page. Empty when no more results remain.
totalintTotal count of results across all pages.

Example response shape (Go):

resp, err := client.Namespaces.ListNamespaces(ctx, &namespaces.ListNamespacesRequest{
Pagination: &policy.PageRequest{Limit: 10, Offset: 0},
})
// resp.GetPagination().GetCurrentOffset() == 0
// resp.GetPagination().GetNextOffset() == 10
// resp.GetPagination().GetTotal() == 42

Namespaces

A namespace is the top-level organizational unit for attributes and optionally for registered resources. FQNs are scoped to a namespace URI (e.g., https://example.com).

Soft-delete only

Namespaces are deactivated, not permanently deleted. There is no hard-delete operation and no restore operation exposed via the SDK.

Create a Namespace

Signature

client.Namespaces.CreateNamespace(ctx, &namespaces.CreateNamespaceRequest{...})

Parameters

ParameterTypeRequiredDescription
namestringYesA valid hostname (e.g., opentdf.io, example.com).
metadataMetadataNoOptional labels, e.g., {"labels": {"owner": "platform-team"}}.

Example

import "github.com/opentdf/platform/protocol/go/policy/namespaces"

resp, err := client.Namespaces.CreateNamespace(context.Background(),
&namespaces.CreateNamespaceRequest{
Name: "opentdf.io",
},
)
if err != nil {
log.Fatal(err)
}
log.Printf("Created namespace: %s\n", resp.GetNamespace().GetId())

With metadata:

import (
"github.com/opentdf/platform/protocol/go/common"
"github.com/opentdf/platform/protocol/go/policy/namespaces"
)

resp, err := client.Namespaces.CreateNamespace(context.Background(),
&namespaces.CreateNamespaceRequest{
Name: "opentdf.io",
Metadata: &common.MetadataMutable{
Labels: map[string]string{
"owner": "platform-team",
"env": "production",
},
},
},
)

Returns

The created Namespace object.

List Namespaces

Signature

client.Namespaces.ListNamespaces(ctx, &namespaces.ListNamespacesRequest{...})

Parameters

ParameterTypeRequiredDescription
statestringNoFilter by state: ACTIVE_STATE_ENUM_ACTIVE (default), ACTIVE_STATE_ENUM_INACTIVE, or ACTIVE_STATE_ENUM_ANY.
pagination.limitintNoMaximum results per page. Defaults to the platform-configured limit.
pagination.offsetintNoNumber of results to skip.

Example

import (
"github.com/opentdf/platform/protocol/go/common"
"github.com/opentdf/platform/protocol/go/policy/namespaces"
)

// List all active namespaces
resp, err := client.Namespaces.ListNamespaces(context.Background(), &namespaces.ListNamespacesRequest{})
if err != nil {
log.Fatal(err)
}
for _, namespace := range resp.GetNamespaces() {
log.Printf("Namespace: %s\n", namespace.GetName())
}

To list inactive namespaces or paginate:

import (
"github.com/opentdf/platform/protocol/go/common"
"github.com/opentdf/platform/protocol/go/policy"
"github.com/opentdf/platform/protocol/go/policy/namespaces"
)

resp, err := client.Namespaces.ListNamespaces(context.Background(), &namespaces.ListNamespacesRequest{
State: common.ActiveStateEnum_ACTIVE_STATE_ENUM_INACTIVE,
Pagination: &policy.PageRequest{
Limit: 10,
Offset: 0,
},
})

Returns

A list of Namespace objects. Includes pagination metadata.

Get a Namespace

Signature

client.Namespaces.GetNamespace(ctx, &namespaces.GetNamespaceRequest{...})

Parameters

Provide one of the following (exactly one is required):

ParameterTypeDescription
idstring (UUID)The namespace UUID.
fqnstring (URI)The namespace FQN (e.g., https://example.com).

Example

import "github.com/opentdf/platform/protocol/go/policy/namespaces"
// Look up by UUID
resp, err := client.Namespaces.GetNamespace(context.Background(),
&namespaces.GetNamespaceRequest{
Identifier: &namespaces.GetNamespaceRequest_NamespaceId{
NamespaceId: "f47ac10b-58cc-4372-a567-0e02b2c3d479",
},
},
)
if err != nil {
log.Fatal(err)
}
log.Printf("Namespace: %s (ID: %s)\n", resp.GetNamespace().GetName(), resp.GetNamespace().GetId())

// Alternatively, look up by FQN
respByFqn, err := client.Namespaces.GetNamespace(context.Background(),
&namespaces.GetNamespaceRequest{
Identifier: &namespaces.GetNamespaceRequest_Fqn{
Fqn: "https://example.com",
},
},
)
if err != nil {
log.Fatal(err)
}
log.Printf("Namespace by FQN: %s\n", respByFqn.GetNamespace().GetName())

Returns

A single Namespace object. Namespace names are unique — an FQN always resolves to exactly one namespace or an error.

Update a Namespace

Signature

client.Namespaces.UpdateNamespace(ctx, &namespaces.UpdateNamespaceRequest{...})

Parameters

ParameterTypeRequiredDescription
idstring (UUID)YesThe namespace ID to update.
metadataMetadataNoLabels to attach, e.g., {"labels": {"owner": "platform-team"}}.
metadataUpdateBehaviorstringNoMETADATA_UPDATE_ENUM_REPLACE overwrites all existing labels. METADATA_UPDATE_ENUM_EXTEND merges new labels into existing ones. If omitted, defaults to EXTEND.

Example

import (
"github.com/opentdf/platform/protocol/go/common"
"github.com/opentdf/platform/protocol/go/policy/namespaces"
)
resp, err := client.Namespaces.UpdateNamespace(context.Background(),
&namespaces.UpdateNamespaceRequest{
Id: "f47ac10b-58cc-4372-a567-0e02b2c3d479",
Metadata: &common.MetadataMutable{
Labels: map[string]string{
"owner": "platform-team",
"env": "production",
},
},
MetadataUpdateBehavior: common.MetadataUpdateEnum_METADATA_UPDATE_ENUM_REPLACE,
},
)
if err != nil {
log.Fatal(err)
}
log.Printf("Updated namespace ID: %s\n", resp.GetNamespace().GetId())

Returns

The updated Namespace object.

Deactivate a Namespace

Signature

client.Namespaces.DeactivateNamespace(ctx, &namespaces.DeactivateNamespaceRequest{...})

Parameters

ParameterTypeRequiredDescription
idstring (UUID)YesThe namespace ID to deactivate.

Example

import "github.com/opentdf/platform/protocol/go/policy/namespaces"
_, err = client.Namespaces.DeactivateNamespace(context.Background(),
&namespaces.DeactivateNamespaceRequest{
Id: "f47ac10b-58cc-4372-a567-0e02b2c3d479",
},
)
if err != nil {
log.Fatal(err)
}
log.Println("Namespace deactivated.")

Returns

Empty response. The namespace is soft-deleted and will no longer appear in ListNamespaces unless you filter by INACTIVE or ANY state.

Namespace Object

FieldTypeDescription
idstring (UUID)Unique identifier, generated by the platform.
namestringThe hostname used to scope attributes (e.g., opentdf.io).
fqnstringFully qualified name, e.g., https://opentdf.io.
activebooltrue until explicitly deactivated.
metadataMetadataOptional labels.
createdAttimestampWhen the namespace was created.
updatedAttimestampWhen the namespace was last modified.

Attributes

An attribute defines a classification dimension (e.g., classification, department). Each attribute belongs to a namespace, has a rule (All Of, Any Of, or Hierarchy), and contains one or more values.

Soft-delete only

Attributes and attribute values are deactivated, not permanently deleted.

Create an Attribute

Signature

client.Attributes.CreateAttribute(ctx, &attributes.CreateAttributeRequest{...})

Parameters

ParameterTypeRequiredDescription
namespaceIdstring (UUID)YesThe parent namespace ID.
namestringYesAttribute name (e.g., classification, department).
rulestringYesAccess rule: ATTRIBUTE_RULE_TYPE_ENUM_ALL_OF, ANY_OF, or HIERARCHY.
values[]stringNoInitial values to create with the attribute. Can also be added later via Create an Attribute Value.
metadataMetadataNoOptional labels.

Example

import (
"github.com/opentdf/platform/protocol/go/policy"
"github.com/opentdf/platform/protocol/go/policy/attributes"
)

resp, err := client.Attributes.CreateAttribute(context.Background(),
&attributes.CreateAttributeRequest{
NamespaceId: "f47ac10b-58cc-4372-a567-0e02b2c3d479",
Name: "classification",
Rule: policy.AttributeRuleTypeEnum_ATTRIBUTE_RULE_TYPE_ENUM_ANY_OF,
Values: []string{"public", "confidential", "secret"},
},
)
if err != nil {
log.Fatal(err)
}
log.Printf("Created attribute: %s (ID: %s)\n",
resp.GetAttribute().GetName(), resp.GetAttribute().GetId())

Returns

The created Attribute object.

List Attributes

Signature

client.Attributes.ListAttributes(ctx, &attributes.ListAttributesRequest{...})

Parameters

ParameterTypeRequiredDescription
statestringNoFilter by state: ACTIVE_STATE_ENUM_ACTIVE (default), ACTIVE_STATE_ENUM_INACTIVE, or ACTIVE_STATE_ENUM_ANY.
namespaceIdstring (UUID)NoFilter to attributes in a specific namespace.
pagination.limitintNoMaximum results per page.
pagination.offsetintNoNumber of results to skip.

Example

import "github.com/opentdf/platform/protocol/go/policy/attributes"

resp, err := client.Attributes.ListAttributes(context.Background(),
&attributes.ListAttributesRequest{},
)
if err != nil {
log.Fatal(err)
}

for _, attr := range resp.GetAttributes() {
log.Printf("Attribute: %s (ID: %s)\n", attr.GetName(), attr.GetId())
for _, value := range attr.GetValues() {
log.Printf(" Value: %s (ID: %s)\n", value.GetValue(), value.GetId())
}
}

Returns

A list of Attribute objects, each with nested values. Includes pagination metadata.

Get an Attribute

Signature

client.Attributes.GetAttribute(ctx, &attributes.GetAttributeRequest{...})

Parameters

Provide one of the following (exactly one is required):

ParameterTypeDescription
idstring (UUID)The attribute UUID.
fqnstringThe attribute FQN (e.g., https://example.com/attr/classification).

Example

import "github.com/opentdf/platform/protocol/go/policy/attributes"

resp, err := client.Attributes.GetAttribute(context.Background(),
&attributes.GetAttributeRequest{
Identifier: &attributes.GetAttributeRequest_Fqn{
Fqn: "https://example.com/attr/classification",
},
},
)
if err != nil {
log.Fatal(err)
}
attr := resp.GetAttribute()
log.Printf("Attribute: %s, Rule: %s\n", attr.GetName(), attr.GetRule())
for _, v := range attr.GetValues() {
log.Printf(" Value: %s (ID: %s)\n", v.GetValue(), v.GetId())
}

Returns

A single Attribute object with nested values.

Update an Attribute

Signature

client.Attributes.UpdateAttribute(ctx, &attributes.UpdateAttributeRequest{...})

Parameters

ParameterTypeRequiredDescription
idstring (UUID)YesThe attribute ID to update.
metadataMetadataNoOptional labels.
metadataUpdateBehaviorstringNoMETADATA_UPDATE_ENUM_REPLACE or METADATA_UPDATE_ENUM_EXTEND (default).

Example

import (
"github.com/opentdf/platform/protocol/go/common"
"github.com/opentdf/platform/protocol/go/policy/attributes"
)

resp, err := client.Attributes.UpdateAttribute(context.Background(),
&attributes.UpdateAttributeRequest{
Id: "a1b2c3d4-0000-0000-0000-000000000001",
Metadata: &common.MetadataMutable{
Labels: map[string]string{"reviewed": "true"},
},
MetadataUpdateBehavior: common.MetadataUpdateEnum_METADATA_UPDATE_ENUM_EXTEND,
},
)
if err != nil {
log.Fatal(err)
}
log.Printf("Updated attribute ID: %s\n", resp.GetAttribute().GetId())

Returns

The updated Attribute object.

Deactivate an Attribute

Signature

client.Attributes.DeactivateAttribute(ctx, &attributes.DeactivateAttributeRequest{...})

Parameters

ParameterTypeRequiredDescription
idstring (UUID)YesThe attribute ID to deactivate.

Example

import "github.com/opentdf/platform/protocol/go/policy/attributes"

resp, err := client.Attributes.DeactivateAttribute(context.Background(),
&attributes.DeactivateAttributeRequest{
Id: "a1b2c3d4-0000-0000-0000-000000000001",
},
)
if err != nil {
log.Fatal(err)
}
log.Printf("Deactivated attribute: %s\n", resp.GetAttribute().GetId())

Returns

Empty response. The attribute is soft-deleted and will no longer appear in ListAttributes unless you filter by INACTIVE or ANY state.

Attribute Values

Attribute values are the individual members of an attribute (e.g., secret, top-secret under classification). They can be managed independently after the parent attribute is created.

Create an Attribute Value

Signature

client.Attributes.CreateAttributeValue(ctx, &attributes.CreateAttributeValueRequest{...})

Parameters

ParameterTypeRequiredDescription
attributeIdstring (UUID)YesThe parent attribute ID.
valuestringYesThe value string (e.g., top-secret).
metadataMetadataNoOptional labels.

Example

import "github.com/opentdf/platform/protocol/go/policy/attributes"

resp, err := client.Attributes.CreateAttributeValue(context.Background(),
&attributes.CreateAttributeValueRequest{
AttributeId: "a1b2c3d4-0000-0000-0000-000000000001",
Value: "top-secret",
},
)
if err != nil {
log.Fatal(err)
}
log.Printf("Created value: %s (ID: %s)\n", resp.GetValue().GetValue(), resp.GetValue().GetId())

Returns

The created Attribute Value object.

List Attribute Values

Signature

client.Attributes.ListAttributeValues(ctx, &attributes.ListAttributeValuesRequest{...})

Parameters

ParameterTypeRequiredDescription
attributeIdstring (UUID)YesThe parent attribute ID.
statestringNoFilter by state: ACTIVE_STATE_ENUM_ACTIVE (default), ACTIVE_STATE_ENUM_INACTIVE, or ACTIVE_STATE_ENUM_ANY.

Example

import "github.com/opentdf/platform/protocol/go/policy/attributes"

resp, err := client.Attributes.ListAttributeValues(context.Background(),
&attributes.ListAttributeValuesRequest{
AttributeId: "a1b2c3d4-0000-0000-0000-000000000001",
},
)
if err != nil {
log.Fatal(err)
}
for _, v := range resp.GetValues() {
log.Printf("Value: %s (ID: %s)\n", v.GetValue(), v.GetId())
}

Returns

A list of Attribute Value objects.

Get an Attribute Value

Signature

client.Attributes.GetAttributeValue(ctx, &attributes.GetAttributeValueRequest{...})

Parameters

Provide one of the following (exactly one is required):

ParameterTypeDescription
idstring (UUID)The value UUID.
fqnstringThe value FQN (e.g., https://example.com/attr/classification/value/secret).

Example

import "github.com/opentdf/platform/protocol/go/policy/attributes"

resp, err := client.Attributes.GetAttributeValue(context.Background(),
&attributes.GetAttributeValueRequest{
Identifier: &attributes.GetAttributeValueRequest_Fqn{
Fqn: "https://example.com/attr/classification/value/secret",
},
},
)
if err != nil {
log.Fatal(err)
}
log.Printf("Value: %s (FQN: %s)\n", resp.GetValue().GetValue(), resp.GetValue().GetFqn())

Returns

A single Attribute Value object.

Get Attribute Values by FQNs

Batch-fetch multiple attribute values by their FQNs in a single request. Returns a map keyed by FQN, each entry containing both the parent attribute definition and the specific value.

Signature

client.Attributes.GetAttributeValuesByFqns(ctx, &attributes.GetAttributeValuesByFqnsRequest{...})

Parameters

ParameterTypeRequiredDescription
fqns[]stringYesAttribute value FQNs to look up.

Example

import "github.com/opentdf/platform/protocol/go/policy/attributes"

resp, err := client.Attributes.GetAttributeValuesByFqns(context.Background(),
&attributes.GetAttributeValuesByFqnsRequest{
Fqns: []string{
"https://example.com/attr/classification/value/secret",
"https://example.com/attr/department/value/engineering",
},
},
)
if err != nil {
log.Fatal(err)
}
for fqn, entry := range resp.GetFqnAttributeValues() {
log.Printf("FQN: %s -> Attribute: %s, Value: %s\n",
fqn, entry.GetAttribute().GetName(), entry.GetValue().GetValue())
}

Returns

A map of FQN to {attribute, value} pairs. Each entry contains the parent Attribute object and the specific Attribute Value object.

Update an Attribute Value

Signature

client.Attributes.UpdateAttributeValue(ctx, &attributes.UpdateAttributeValueRequest{...})

Parameters

ParameterTypeRequiredDescription
idstring (UUID)YesThe value ID to update.
metadataMetadataNoOptional labels.
metadataUpdateBehaviorstringNoMETADATA_UPDATE_ENUM_REPLACE or METADATA_UPDATE_ENUM_EXTEND (default).

Example

import (
"github.com/opentdf/platform/protocol/go/common"
"github.com/opentdf/platform/protocol/go/policy/attributes"
)

resp, err := client.Attributes.UpdateAttributeValue(context.Background(),
&attributes.UpdateAttributeValueRequest{
Id: "v1b2c3d4-0000-0000-0000-000000000001",
Metadata: &common.MetadataMutable{
Labels: map[string]string{"deprecated": "false"},
},
MetadataUpdateBehavior: common.MetadataUpdateEnum_METADATA_UPDATE_ENUM_EXTEND,
},
)
if err != nil {
log.Fatal(err)
}
log.Printf("Updated value ID: %s\n", resp.GetValue().GetId())

Returns

The updated Attribute Value object.

Deactivate an Attribute Value

Signature

client.Attributes.DeactivateAttributeValue(ctx, &attributes.DeactivateAttributeValueRequest{...})

Parameters

ParameterTypeRequiredDescription
idstring (UUID)YesThe value ID to deactivate.

Example

import "github.com/opentdf/platform/protocol/go/policy/attributes"

resp, err := client.Attributes.DeactivateAttributeValue(context.Background(),
&attributes.DeactivateAttributeValueRequest{
Id: "v1b2c3d4-0000-0000-0000-000000000001",
},
)
if err != nil {
log.Fatal(err)
}
log.Printf("Deactivated value: %s\n", resp.GetValue().GetId())

Returns

Empty response. The value is soft-deleted and will no longer appear in listings unless you filter by INACTIVE or ANY state.

Attribute Object

FieldTypeDescription
idstring (UUID)Unique identifier, generated by the platform.
namestringThe attribute name (e.g., department, clearance).
fqnstringFully qualified name, e.g., https://opentdf.io/attr/department.
rulestringAccess rule: ATTRIBUTE_RULE_TYPE_ENUM_ALL_OF, ATTRIBUTE_RULE_TYPE_ENUM_ANY_OF, or ATTRIBUTE_RULE_TYPE_ENUM_HIERARCHY.
values[]ValueThe attribute values defined under this attribute.
namespaceNamespaceThe parent Namespace.
activebooltrue until explicitly deactivated.
metadataMetadataOptional labels.
createdAttimestampWhen the attribute was created.
updatedAttimestampWhen the attribute was last modified.

Attribute Value Object

FieldTypeDescription
idstring (UUID)Unique identifier, generated by the platform.
valuestringThe value string (e.g., finance, confidential).
fqnstringFully qualified name, e.g., https://opentdf.io/attr/department/value/finance.
attributeAttributeThe parent Attribute.
activebooltrue until explicitly deactivated.
metadataMetadataOptional labels.
createdAttimestampWhen the value was created.
updatedAttimestampWhen the value was last modified.

Subject Condition Sets

A subject condition set (SCS) is a reusable, named set of conditions that evaluate claims from an entity's token. Multiple subject mappings can reference the same SCS.

Hard-delete

Subject condition sets are permanently deleted (not deactivated).

Create a Subject Condition Set

Signature

client.SubjectMapping.CreateSubjectConditionSet(ctx, &subjectmapping.CreateSubjectConditionSetRequest{...})

Parameters

ParameterTypeRequiredDescription
subjectConditionSet.subjectSets[]SubjectSetYesOne or more subject sets. Each contains condition groups with conditions that match against entity token claims. Subject sets are evaluated with AND logic. See Condition Structure.
metadataMetadataNoOptional labels.

Example

import (
"github.com/opentdf/platform/protocol/go/policy"
"github.com/opentdf/platform/protocol/go/policy/subjectmapping"
)

// Create Subject Condition Set

conditionset := &subjectmapping.CreateSubjectConditionSetRequest{
SubjectConditionSet: &subjectmapping.SubjectConditionSetCreate{
SubjectSets: []*policy.SubjectSet{
{
ConditionGroups: []*policy.ConditionGroup{
{
BooleanOperator: policy.ConditionBooleanTypeEnum_CONDITION_BOOLEAN_TYPE_ENUM_AND,
Conditions: []*policy.Condition{
{
SubjectExternalSelectorValue: ".clientId",
Operator: policy.SubjectMappingOperatorEnum_SUBJECT_MAPPING_OPERATOR_ENUM_IN,
SubjectExternalValues: []string{"opentdf"},
},
},
},
},
},
},
},
}

resp, err := client.SubjectMapping.CreateSubjectConditionSet(context.Background(), conditionset)
if err != nil {
log.Fatal(err)
}

log.Printf("Created Subject Condition Set with ID: %s\n", resp.GetSubjectConditionSet().GetId())

Returns

The created Subject Condition Set object.

List Subject Condition Sets

Signature

client.SubjectMapping.ListSubjectConditionSets(ctx, &subjectmapping.ListSubjectConditionSetsRequest{...})

Parameters

ParameterTypeRequiredDescription
namespaceIdstring (UUID)NoFilter to condition sets in this namespace.
namespaceFqnstring (URI)NoFilter by namespace FQN (e.g., https://example.com). Alternative to namespaceId.
pagination.limitintNoMaximum results per page.
pagination.offsetintNoNumber of results to skip.

Without a namespace filter, returns all subject condition sets across all namespaces.

Example

import "github.com/opentdf/platform/protocol/go/policy/subjectmapping"

resp, err := client.SubjectMapping.ListSubjectConditionSets(context.Background(),
&subjectmapping.ListSubjectConditionSetsRequest{},
)
if err != nil {
log.Fatal(err)
}
for _, scs := range resp.GetSubjectConditionSets() {
log.Printf("SCS ID: %s\n", scs.GetId())
}

Returns

A list of Subject Condition Set objects. Includes pagination metadata.

Get a Subject Condition Set

Signature

client.SubjectMapping.GetSubjectConditionSet(ctx, &subjectmapping.GetSubjectConditionSetRequest{...})

Parameters

ParameterTypeRequiredDescription
idstring (UUID)YesThe subject condition set ID.

Example

import "github.com/opentdf/platform/protocol/go/policy/subjectmapping"

resp, err := client.SubjectMapping.GetSubjectConditionSet(context.Background(),
&subjectmapping.GetSubjectConditionSetRequest{
Id: "a0b1c2d3-0000-0000-0000-000000000099",
},
)
if err != nil {
log.Fatal(err)
}
scs := resp.GetSubjectConditionSet()
log.Printf("SCS ID: %s\n", scs.GetId())
log.Printf("Associated subject mappings: %d\n", len(resp.GetAssociatedSubjectMappings()))

Returns

The Subject Condition Set object, plus associatedSubjectMappings — all subject mappings currently referencing this condition set.

Update a Subject Condition Set

Signature

client.SubjectMapping.UpdateSubjectConditionSet(ctx, &subjectmapping.UpdateSubjectConditionSetRequest{...})

Parameters

ParameterTypeRequiredDescription
idstring (UUID)YesThe subject condition set ID to update.
subjectSets[]SubjectSetNoReplaces the entire condition tree. Omit to update metadata only.
metadataMetadataNoOptional labels.
metadataUpdateBehaviorstringNoMETADATA_UPDATE_ENUM_REPLACE or METADATA_UPDATE_ENUM_EXTEND (default).

Example

Providing SubjectSets replaces the entire condition tree. Omit it to update metadata only.

import (
"github.com/opentdf/platform/protocol/go/policy"
"github.com/opentdf/platform/protocol/go/policy/subjectmapping"
)
resp, err := client.SubjectMapping.UpdateSubjectConditionSet(context.Background(),
&subjectmapping.UpdateSubjectConditionSetRequest{
Id: "a0b1c2d3-0000-0000-0000-000000000099",
SubjectSets: []*policy.SubjectSet{
{
ConditionGroups: []*policy.ConditionGroup{
{
BooleanOperator: policy.ConditionBooleanTypeEnum_CONDITION_BOOLEAN_TYPE_ENUM_AND,
Conditions: []*policy.Condition{
{
SubjectExternalSelectorValue: ".clientId",
Operator: policy.SubjectMappingOperatorEnum_SUBJECT_MAPPING_OPERATOR_ENUM_IN,
SubjectExternalValues: []string{"my-service", "my-other-service"},
},
},
},
},
},
},
},
)
if err != nil {
log.Fatal(err)
}
log.Printf("Updated SCS ID: %s\n", resp.GetSubjectConditionSet().GetId())

Returns

The updated Subject Condition Set object.

Delete a Subject Condition Set

Signature

client.SubjectMapping.DeleteSubjectConditionSet(ctx, &subjectmapping.DeleteSubjectConditionSetRequest{...})

Parameters

ParameterTypeRequiredDescription
idstring (UUID)YesThe subject condition set ID to delete.

Example

import "github.com/opentdf/platform/protocol/go/policy/subjectmapping"
resp, err := client.SubjectMapping.DeleteSubjectConditionSet(context.Background(),
&subjectmapping.DeleteSubjectConditionSetRequest{
Id: "a0b1c2d3-0000-0000-0000-000000000099",
},
)
if err != nil {
log.Fatal(err)
}
log.Printf("Deleted SCS ID: %s\n", resp.GetSubjectConditionSet().GetId())

Returns

The deleted Subject Condition Set object. This is a hard delete — the object is permanently removed.

Delete All Unmapped Subject Condition Sets

Permanently deletes all subject condition sets that are not referenced by any subject mapping. Use this as a maintenance operation to clean up orphaned condition sets.

Signature

client.SubjectMapping.DeleteAllUnmappedSubjectConditionSets(ctx, &subjectmapping.DeleteAllUnmappedSubjectConditionSetsRequest{})

Parameters

None.

Example

import "github.com/opentdf/platform/protocol/go/policy/subjectmapping"
resp, err := client.SubjectMapping.DeleteAllUnmappedSubjectConditionSets(context.Background(),
&subjectmapping.DeleteAllUnmappedSubjectConditionSetsRequest{},
)
if err != nil {
log.Fatal(err)
}
log.Printf("Deleted %d unmapped subject condition sets.\n", len(resp.GetSubjectConditionSets()))

Returns

A list of all deleted Subject Condition Set objects.

Subject Condition Set Object

FieldTypeDescription
idstring (UUID)Unique identifier, generated by the platform.
subjectSets[]SubjectSetOne or more subject sets, evaluated with AND logic — all must match.
namespaceNamespaceThe parent Namespace, if assigned.
metadataMetadataOptional labels.
createdAttimestampWhen the condition set was created.
updatedAttimestampWhen the condition set was last modified.

Condition Structure

A Subject Condition Set contains a tree of nested objects that define which entities match. Here's how they fit together:

SubjectConditionSet
└── subjectSets[] ← AND across sets
└── conditionGroups[] ← AND across groups
├── booleanOperator ← AND or OR across conditions within this group
└── conditions[]
├── subjectExternalSelectorValue ← claim path (e.g., ".clientId")
├── operator ← IN, NOT_IN, or IN_CONTAINS
└── subjectExternalValues[] ← expected values

Evaluation logic: All subject sets must match (AND). Within each set, all condition groups must match (AND). Within each group, conditions are combined by the group's booleanOperator (AND or OR).

SubjectSet

FieldTypeDescription
conditionGroups[]ConditionGroupOne or more condition groups. All groups must match (AND logic).

ConditionGroup

FieldTypeDescription
booleanOperatorstringHow to combine conditions: CONDITION_BOOLEAN_TYPE_ENUM_AND or CONDITION_BOOLEAN_TYPE_ENUM_OR.
conditions[]ConditionOne or more conditions to evaluate.

Condition

A single claim match against an entity's token.

FieldTypeDescription
subjectExternalSelectorValuestringA selector path into the entity's flattened token claims (e.g., .clientId, .realm_access.roles).
operatorstringComparison operator (see below).
subjectExternalValues[]stringThe values to compare against.

Operators:

OperatorDescription
SUBJECT_MAPPING_OPERATOR_ENUM_INThe claim value must exactly match one of the subjectExternalValues.
SUBJECT_MAPPING_OPERATOR_ENUM_NOT_INThe claim value must not match any of the subjectExternalValues.
SUBJECT_MAPPING_OPERATOR_ENUM_IN_CONTAINSThe claim value must contain (substring match) one of the subjectExternalValues.

Example: "Match entities whose .clientId is my-service AND whose .realm_access.roles contains developer":

{
"subjectSets": [
{
"conditionGroups": [
{
"booleanOperator": "CONDITION_BOOLEAN_TYPE_ENUM_AND",
"conditions": [
{
"subjectExternalSelectorValue": ".clientId",
"operator": "SUBJECT_MAPPING_OPERATOR_ENUM_IN",
"subjectExternalValues": ["my-service"]
},
{
"subjectExternalSelectorValue": ".realm_access.roles",
"operator": "SUBJECT_MAPPING_OPERATOR_ENUM_IN_CONTAINS",
"subjectExternalValues": ["developer"]
}
]
}
]
}
]
}

SubjectProperty

Used in MatchSubjectMappings to test which subject mappings match a given set of entity claims.

FieldTypeDescription
externalSelectorValuestringA selector path into the entity's token claims (e.g., .clientId, .realm_access.roles).
externalValuestringThe claim value to test against (e.g., my-service, developer).

Subject Mappings

A subject mapping links a subject condition set to a specific attribute value and a set of permitted actions (e.g., DECRYPT). It answers the question: "which entities are allowed to do what with data carrying this attribute value?"

Hard-delete

Subject mappings are permanently deleted (not deactivated). There is no restore operation.

Create a Subject Mapping

Signature

client.SubjectMapping.CreateSubjectMapping(ctx, &subjectmapping.CreateSubjectMappingRequest{...})

Parameters

ParameterTypeRequiredDescription
attributeValueIdstring (UUID)YesThe attribute value this mapping grants access to.
actions[]ActionYesPermitted actions (e.g., read, create).
existingSubjectConditionSetIdstring (UUID)Yes*ID of an existing subject condition set. Required unless newSubjectConditionSet is provided.
newSubjectConditionSetobjectYes*Create a new condition set inline. Required unless existingSubjectConditionSetId is provided. Contains a subjectSets array — see Condition Structure.
metadataMetadataNoOptional labels.

Example

import (
"github.com/opentdf/platform/protocol/go/policy"
"github.com/opentdf/platform/protocol/go/policy/subjectmapping"
)

// Create Subject Mapping
subjectMapping := &subjectmapping.CreateSubjectMappingRequest{
AttributeValueId: "224c9d29-2cd4-4a38-b6ad-5f025ca93a8c",
Actions: []*policy.Action{
{
Value: &policy.Action_Standard{
Standard: policy.Action_STANDARD_ACTION_DECRYPT,
},
},
},
ExistingSubjectConditionSetId: "890b26db-4ee4-447f-ae8a-2862d922eeef",
}

_, err = client.SubjectMapping.CreateSubjectMapping(context.Background(), subjectMapping)
if err != nil {
log.Fatal(err)
}

Returns

The created Subject Mapping object.

List Subject Mappings

Signature

client.SubjectMapping.ListSubjectMappings(ctx, &subjectmapping.ListSubjectMappingsRequest{...})

Parameters

ParameterTypeRequiredDescription
namespaceIdstring (UUID)NoFilter to mappings in this namespace.
namespaceFqnstring (URI)NoFilter by namespace FQN. Alternative to namespaceId.
pagination.limitintNoMaximum results per page.
pagination.offsetintNoNumber of results to skip.

Without a namespace filter, returns all subject mappings across all namespaces.

Example

import "github.com/opentdf/platform/protocol/go/policy/subjectmapping"

// List Subject Mapping

subjectmappings, err := client.SubjectMapping.ListSubjectMappings(context.Background(), &subjectmapping.ListSubjectMappingsRequest{})
if err != nil {
log.Fatal(err)
}

for _, sm := range subjectmappings.GetSubjectMappings() {
log.Printf("Subject Mapping: %s", sm.GetId())
}

Returns

A list of Subject Mapping objects. Includes pagination metadata.

Get a Subject Mapping

Signature

client.SubjectMapping.GetSubjectMapping(ctx, &subjectmapping.GetSubjectMappingRequest{...})

Parameters

ParameterTypeRequiredDescription
idstring (UUID)YesThe subject mapping ID.

Example

import "github.com/opentdf/platform/protocol/go/policy/subjectmapping"

resp, err := client.SubjectMapping.GetSubjectMapping(context.Background(),
&subjectmapping.GetSubjectMappingRequest{
Id: "890b26db-4ee4-447f-ae8a-2862d922eeef",
},
)
if err != nil {
log.Fatal(err)
}
sm := resp.GetSubjectMapping()
log.Printf("Subject Mapping ID: %s, Attribute Value ID: %s\n",
sm.GetId(), sm.GetAttributeValue().GetId())

Returns

A single Subject Mapping object.

Update a Subject Mapping

Signature

client.SubjectMapping.UpdateSubjectMapping(ctx, &subjectmapping.UpdateSubjectMappingRequest{...})

Parameters

ParameterTypeRequiredDescription
idstring (UUID)YesThe subject mapping ID to update.
actions[]ActionNoReplaces the entire actions list. Omit to leave unchanged.
subjectConditionSetIdstring (UUID)NoSwap the linked condition set.
metadataMetadataNoOptional labels.
metadataUpdateBehaviorstringNoMETADATA_UPDATE_ENUM_REPLACE or METADATA_UPDATE_ENUM_EXTEND (default).

Example

import (
"github.com/opentdf/platform/protocol/go/policy"
"github.com/opentdf/platform/protocol/go/policy/subjectmapping"
)

resp, err := client.SubjectMapping.UpdateSubjectMapping(context.Background(),
&subjectmapping.UpdateSubjectMappingRequest{
Id: "890b26db-4ee4-447f-ae8a-2862d922eeef",
Actions: []*policy.Action{
{
Value: &policy.Action_Standard{
Standard: policy.Action_STANDARD_ACTION_DECRYPT,
},
},
},
},
)
if err != nil {
log.Fatal(err)
}
log.Printf("Updated subject mapping ID: %s\n", resp.GetSubjectMapping().GetId())

Returns

The updated Subject Mapping object.

Delete a Subject Mapping

Signature

client.SubjectMapping.DeleteSubjectMapping(ctx, &subjectmapping.DeleteSubjectMappingRequest{...})

Parameters

ParameterTypeRequiredDescription
idstring (UUID)YesThe subject mapping ID to delete.

Example

import "github.com/opentdf/platform/protocol/go/policy/subjectmapping"

resp, err := client.SubjectMapping.DeleteSubjectMapping(context.Background(),
&subjectmapping.DeleteSubjectMappingRequest{
Id: "890b26db-4ee4-447f-ae8a-2862d922eeef",
},
)
if err != nil {
log.Fatal(err)
}
log.Printf("Deleted subject mapping ID: %s\n", resp.GetSubjectMapping().GetId())

Returns

The deleted Subject Mapping object. This is a hard delete — the object is permanently removed.

Match Subject Mappings

Given a list of subject properties (key-value pairs from an entity's token claims), returns all subject mappings whose condition sets match. Use this to determine which access grants apply to a given entity.

Signature

client.SubjectMapping.MatchSubjectMappings(ctx, &subjectmapping.MatchSubjectMappingsRequest{...})

Parameters

ParameterTypeRequiredDescription
subjectProperties[]SubjectPropertyYesKey-value pairs from an entity's claims. Each has externalSelectorValue (the claim path, e.g., .clientId) and externalValue (the claim value).

Example

import (
"github.com/opentdf/platform/protocol/go/policy"
"github.com/opentdf/platform/protocol/go/policy/subjectmapping"
)

resp, err := client.SubjectMapping.MatchSubjectMappings(context.Background(),
&subjectmapping.MatchSubjectMappingsRequest{
SubjectProperties: []*policy.SubjectProperty{
{ExternalSelectorValue: ".clientId", ExternalValue: "my-service"},
{ExternalSelectorValue: ".realm_access.roles", ExternalValue: "developer"},
},
},
)
if err != nil {
log.Fatal(err)
}
for _, sm := range resp.GetSubjectMappings() {
log.Printf("Matched subject mapping ID: %s\n", sm.GetId())
}

Returns

A list of Subject Mapping objects whose condition sets matched the provided subject properties.

Action

An action represents what an entity is permitted to do with data. The platform ships with four standard actions that cannot be deleted:

Standard ActionDescription
readRead/decrypt data. Used in all TDF decrypt flows.
createCreate new data.
updateUpdate existing data.
deleteDelete data.

You can also define custom actions (e.g., download, queue-to-print, send_email). Custom actions are globally unique, not namespaced, and are lowercased when stored. See Actions for more.

Actions are specified by name in the SDK:

// Go
&policy.Action{Name: "read"}
// Java
Action.newBuilder().setName("read").build();
// JavaScript
{ name: 'read' }

Subject Mapping Object

FieldTypeDescription
idstring (UUID)Unique identifier, generated by the platform.
attributeValueValueThe Attribute Value this mapping grants access to.
subjectConditionSetSubjectConditionSetThe Subject Condition Set that determines which entities match.
actions[]ActionPermitted actions (e.g., read, create).
namespaceNamespaceThe parent Namespace, if assigned.
metadataMetadataOptional labels.
createdAttimestampWhen the mapping was created.
updatedAttimestampWhen the mapping was last modified.