Skip to main content

Search & Filter Access

The Search endpoints answer the list and filter questions: which resources can a subject act on?, which subjects can act on a resource?, which actions can a subject take? Uniquely, they can return a UCAST-style filter: a condition tree you push into your own data store to filter large datasets by policy without evaluating each row.

Natively conformant with the AuthZEN 1.0 Search API.

POST /access/v1/search/resource # which resources can subject do action on?
POST /access/v1/search/subject # which subjects can do action on resource?
POST /access/v1/search/action # which actions can subject do on resource?

Two modes: filter vs results

Set via options.return (default filter):

"UCAST-style" means the tree follows the shape popularized by UCAST (a type / operator / conditions node tree): it is Vengtoo's own condition tree, not a spec we claim conformance to.

ModeReturnsUse when
filterA UCAST-style predicate describing all matching rowsYour data lives in your store (large / unregistered): push the filter into your query
resultsA concrete list of registered resources/subjects (RBAC)Your resources are registered in Vengtoo
bothfilter + results

For enumerating registered resources without a filter, results mode is equivalent to the reverse-query capability. The filter mode is what lets you filter data Vengtoo never stores. The filter mode returns a UCAST-style predicate (see the filter format).

Request

Headers

HeaderValue
AuthorizationBearer vgt_...
Content-Typeapplication/json

Omit resource.id: you're asking about all resources of the type:

{
"subject": { "external_id": "alice", "type": "user" },
"action": { "name": "read" },
"resource": { "type": "document" },
"options": { "return": "filter" }
}
  • subject search: omit subject.id (asks which subjects can do the action).
  • action search: omit the action (asks which actions the subject can take); returns an action list.

Response

filter mode

{
"filter": {
"type": "logical",
"operator": "and",
"conditions": [
{ "type": "field", "field": "owner", "operator": "eq", "value": "alice" },
{ "type": "logical", "operator": "not",
"conditions": [ { "type": "field", "field": "status", "operator": "eq", "value": "archived" } ] }
]
},
"context": { "reason": "policy matched", "access_paths": ["direct"] }
}

results mode

{
"results": [ { "resource_id": "doc-1", "actions": ["read"], "access_path": "role" } ],
"context": { "reason": "policy matched" }
}

The filter format (UCAST-style)

The filter is a UCAST-style condition tree: Vengtoo's own predicate AST, following the UCAST (Universal Condition AST) shape rather than conforming to an external spec. Three node types:

NodeShape
field{"type":"field","field":"owner","operator":"eq","value":"alice"}
logical{"type":"logical","operator":"and"|"or"|"not","conditions":[…]}
const{"type":"const","value":true}: true = all rows, false = no rows

Field operators: eq, ne, gt, gte, lt, lte, in, nin, regex.

A pure-RBAC grant (no attribute conditions) yields {"type":"const","value":true} for that path (all rows via that grant); no grant yields {"type":"const","value":false}.

Translate to SQL

The response is a condition tree, not SQL: Vengtoo stays database-agnostic. Each SDK ships a reference ucast_to_sql helper (our own translator; no third-party UCAST dependency) that turns the filter into a parameterized SQL WHERE clause you run against your own database:

resp = vengtoo.search_resource(SearchRequest(...)) # -> resp.filter
where, params = ucast_to_sql(resp.filter) # e.g. "(owner_id = $1) AND ..."
rows = db.execute(f"SELECT * FROM documents WHERE {where}", params)
const resp = await vengtoo.searchResource({ ... }); // -> resp.filter
const { where, params } = ucastToSQL(resp.filter); // "$1, $2, …" placeholders
const rows = await db.query(`SELECT * FROM documents WHERE ${where}`, params);
resp, _ := client.SearchResource(ctx, req) // -> resp.Filter
where, params, _ := vengtoo.UCASTToSQL(resp.Filter, nil) // "$1, $2, …" placeholders
rows, _ := db.QueryContext(ctx, "SELECT * FROM documents WHERE "+where, params...)

It is a Postgres reference translator: it emits $1, $2, … numbered placeholders and maps regex to Postgres' ~; other drivers may need a different placeholder or regex style. Values are always bound as parameters (never string-interpolated), so the output is SQL-injection safe. Pass a field→column map as the second argument when your column names differ from the filter's field names (e.g. {"owner": "owner_id"}); column identifiers are validated before use.

What is not in the filter

Request-time gates are not in the filter

Request-time gates, time windows, IP allowlists, MFA, rate limits, are not encoded in the row filter (they can't be meaningfully expressed as a WHERE clause). They are enforced at the actual access-evaluation call. The filter covers resource attribute conditions and RBAC grants only.

Error responses

StatusDescription
400Invalid request body
401Missing or invalid credential
501Partial evaluation unavailable (e.g., the local agent, which evaluates in-memory)

Example

curl -X POST https://pdp.vengtoo.com/access/v1/search/resource \
-H "Authorization: Bearer vgt_..." \
-H "Content-Type: application/json" \
-d '{
"subject": { "external_id": "alice", "type": "user" },
"action": { "name": "read" },
"resource": { "type": "document" },
"options": { "return": "filter" }
}'