Managing service metadata through the REST API#
Permission Service tracks service metadata — the catalog of services that integrate with authorization, the actions each service exposes, and the resource types those actions operate on. This catalog is exposed as a REST API under /v1beta/services/ so that clients and management tools can discover and update it at runtime.
Metadata is primarily reference information used to understand other service operations. Callers rarely need it to evaluate a request; instead, the Permission UI uses it to drive autocomplete when composing Cedar policies, so policy authors can pick a known service, pick one of its registered actions, and pick one of its registered resource types instead of typing identifiers by hand. The API described on this page is what the UI (and any equivalent tooling) calls to populate those suggestions.
A small number of metadata fields are consumed by the service itself at authorization time:
id_claimon aServiceMetaselects which claim from the caller’s token is used as the principal id for requests that target that service. See idClaim for principals below.evaluation_priorityon aResourceTypeMetacontrols how competing policies are combined for resources of that type. See Evaluation priority for resources below.
All other metadata — the list of services, the names of actions, the set of resource types — is advisory: it is not required for a policy to be stored or evaluated, and the service does not reject unknown services, actions, or resource types at authorization time.
For how policies are written and evaluated, see Writing Cedar policies for Permission Service. For how metadata is seeded from Helm or YAML at startup, see Deployment and Database configuration.
Overview#
The metadata API is a CRUD surface organized around three nested records — services, their actions, and their resource types:
Method |
Path |
Purpose |
|---|---|---|
GET |
|
List all services and their |
GET |
|
Fetch |
PUT |
|
Create or update |
DELETE |
|
Remove |
GET |
|
List registered actions for a service. |
PUT |
|
Replace the full set of actions for a service. |
PUT |
|
Add or update a single action. |
DELETE |
|
Remove a single action. |
GET |
|
List registered resource types for a service. |
PUT |
|
Replace the full set of resource types for a service. |
GET |
|
Fetch |
PUT |
|
Create or update |
DELETE |
|
Remove |
Key behaviors that apply to all endpoints:
Storage backend. Write operations require Postgres mode. In config-file mode the storage is read-only and write endpoints return
501 Not Implemented. Read endpoints are available in both modes. See Deployment for how to select a backend.Path parameters win over the body. For
PUT /v1beta/services/{service}/,PUT /v1beta/services/{service}/actions/, andPUT /v1beta/services/{service}/resource-types/{type}/, theservice(and, where applicable,type) value is taken from the URL; any matching field in the JSON body is overwritten before the record is stored. Clients can safely omit those fields.Cache invalidation. Successful writes invalidate the in-memory metadata and evaluation caches for the affected service so that subsequent reads and authorization requests see the new state immediately.
Seeding metadata at deployment time#
Instead of (or in addition to) calling this API at runtime, metadata can be populated at deployment time through the Helm value database.init.services. Each entry describes one service and optionally its principal idClaim, its registered actions, and its resource types with evaluation priorities. The chart renders the list into a ConfigMap and mounts it at /etc/permission-config/ so the service can load it on startup. See also Metadata file format.
How the seed is applied depends on the storage backend:
Config-file mode — the rendered file is the read-only metadata store; the only way to change metadata in this mode is to update the Helm value and redeploy. The service reloads the file automatically when its modification time changes.
Postgres mode — seeded entries are written into the database on startup, and can be changed afterwards through the REST API described on this page.
The example below seeds the four standard Omniverse services — storage-service, event-consumer-service, event-aggregation-service, and userinfo — with the actions and resource types listed in Actions and resources for Omniverse services:
database:
init:
services:
- name: "storage-service"
principal:
idClaim: "sub"
actions:
- "read"
- "write"
resourceTypes:
- type: "object"
evaluationPriority: "permit"
- type: "folder"
evaluationPriority: "permit"
- name: "event-consumer-service"
actions:
- "consume-all-storage-create-events"
- "consume-all-storage-delete-events"
- "consume-durable-queues"
- "create-durable-queues"
- "delete-durable-queues"
- name: "event-aggregation-service"
actions:
- "publish-event"
resourceTypes:
- type: "EventType"
evaluationPriority: "forbid"
- name: "userinfo"
actions:
- "list-users"
- "get-user"
- "list-user-groups"
- "get-user-group"
- "list-groups"
- "get-group"
- "list-group-members"
- "get-group-member"
resourceTypes:
- type: "User"
- type: "Group"
A few notes on the schema:
principal.idClaimis optional. When it is omitted, the service falls back to the deployment-widePRINCIPAL_ID_CLAIM(defaultsub). See idClaim for principals.actionsare plain names; they are referenced from Cedar policies asAction::"<service>:<name>".resourceTypes[].evaluationPriorityis optional and defaults to"forbid". See Evaluation priority for resources.A service that registers actions only (like
event-consumer-serviceabove) simply omitsresourceTypes; Cedar policies for those actions leave theresourceslot unconstrained.
Records#
Three record shapes appear in request and response bodies.
ServiceMeta — one per service:
{
"service": "storage-service",
"id_claim": "email"
}
Field |
Type |
Description |
|---|---|---|
|
string |
Service name. Matches the |
|
string |
Optional. Claim from the caller’s token used as the principal id for requests targeting this service. See idClaim for principals. Empty string means “unset”; accepts the alias |
Action — one per registered action:
{
"name": "read",
"service": "storage-service"
}
Field |
Type |
Description |
|---|---|---|
|
string |
Action name, up to 255 characters. Used as the |
|
string |
Service the action belongs to. Always matches the |
ResourceTypeMeta — one per resource type:
{
"service": "storage-service",
"type": "object",
"evaluation_priority": "forbid"
}
Field |
Type |
Description |
|---|---|---|
|
string |
Service the resource type belongs to. Matches the |
|
string |
Resource type name. Used as the Cedar entity type (for example |
|
string |
Optional. One of |
GET /v1beta/services/ — list services#
Returns every service registered in the database, each as a ServiceMeta record.
Request#
GET /v1beta/services/ HTTP/1.1
Host: permission-service.storage-apis.svc.cluster.local:3000
Authorization: Bearer <token>
Responses#
Status |
Body |
Meaning |
|---|---|---|
|
|
Services returned; empty array when none are registered. |
|
— |
Missing or invalid bearer token (auth enabled). |
|
error message (string) |
Caller lacks |
|
error message (string) |
Storage failure while reading metadata. |
|
error message (string) |
Storage backend does not support this operation. |
GET /v1beta/services/{service}/ — fetch service metadata#
Returns the ServiceMeta for a single service.
Path parameters#
Name |
Type |
Description |
|---|---|---|
|
string |
Service name. |
Responses#
Status |
Body |
Meaning |
|---|---|---|
|
|
Service found. |
|
— |
Missing or invalid bearer token (auth enabled). |
|
error message (string) |
Caller lacks |
|
error message (string) |
No service with that name is registered. |
|
error message (string) |
Storage failure while reading metadata. |
|
error message (string) |
Storage backend does not support this operation. |
PUT /v1beta/services/{service}/ — update service metadata#
Creates the service record if it does not exist, or updates it in place. The service field of the payload is overwritten with the URL path segment, so the body effectively only needs to carry id_claim.
Path parameters#
Name |
Type |
Description |
|---|---|---|
|
string |
Service name. |
Request#
PUT /v1beta/services/storage-service/ HTTP/1.1
Host: permission-service.storage-apis.svc.cluster.local:3000
Authorization: Bearer <token>
Content-Type: application/json
{
"id_claim": "email"
}
Responses#
Status |
Body |
Meaning |
|---|---|---|
|
|
Metadata stored; the response echoes the record as persisted. |
|
— |
Missing or invalid bearer token (auth enabled). |
|
error message (string) |
Caller lacks |
|
error message (string) |
JSON body failed to deserialize. |
|
error message (string) |
Storage failure while writing metadata. |
|
error message (string) |
Storage backend does not support writes. |
DELETE /v1beta/services/{service}/ — delete service metadata#
Removes the service record, along with its actions and resource types in storage backends that cascade deletes.
Path parameters#
Name |
Type |
Description |
|---|---|---|
|
string |
Service name. |
Responses#
Status |
Body |
Meaning |
|---|---|---|
|
— |
Service removed, or no service with that name existed. |
|
— |
Missing or invalid bearer token (auth enabled). |
|
error message (string) |
Caller lacks |
|
error message (string) |
Storage failure while deleting metadata. |
|
error message (string) |
Storage backend does not support writes. |
GET /v1beta/services/{service}/actions/ — list actions#
Returns every action registered for the service.
Path parameters#
Name |
Type |
Description |
|---|---|---|
|
string |
Service name. |
Responses#
Status |
Body |
Meaning |
|---|---|---|
|
|
Actions returned; empty array when none are registered. |
|
— |
Missing or invalid bearer token (auth enabled). |
|
error message (string) |
Caller lacks |
|
error message (string) |
Storage failure while reading metadata. |
|
error message (string) |
Storage backend does not support this operation. |
PUT /v1beta/services/{service}/actions/ — replace all actions#
Replaces the complete set of actions registered for the service. All existing actions for {service} are deleted and replaced with the supplied list. The service field on every item in the body is overwritten with the URL path segment, so clients can omit it.
An empty array is accepted and clears all actions for the service.
Path parameters#
Name |
Type |
Description |
|---|---|---|
|
string |
Service name. |
Request#
PUT /v1beta/services/storage-service/actions/ HTTP/1.1
Host: permission-service.storage-apis.svc.cluster.local:3000
Authorization: Bearer <token>
Content-Type: application/json
[
{ "name": "read" },
{ "name": "write" }
]
Responses#
Status |
Body |
Meaning |
|---|---|---|
|
— |
Actions replaced. |
|
— |
Missing or invalid bearer token (auth enabled). |
|
error message (string) |
Caller lacks |
|
error message (string) |
JSON body failed to deserialize or an item failed per-field validation (for example, |
|
error message (string) |
Storage failure while writing metadata. |
|
error message (string) |
Storage backend does not support writes. |
PUT /v1beta/services/{service}/actions/{action}/ — add or update a single action#
Registers a single action for the service, or leaves it in place if it already exists. The request has no body; the action name is taken from the URL.
Path parameters#
Name |
Type |
Description |
|---|---|---|
|
string |
Service name. |
|
string |
Action name. |
Responses#
Status |
Body |
Meaning |
|---|---|---|
|
|
Action stored; the response echoes the record. |
|
— |
Missing or invalid bearer token (auth enabled). |
|
error message (string) |
Caller lacks |
|
error message (string) |
Storage failure while writing metadata. |
|
error message (string) |
Storage backend does not support writes. |
DELETE /v1beta/services/{service}/actions/{action}/ — delete an action#
Removes a single action from the service.
Path parameters#
Name |
Type |
Description |
|---|---|---|
|
string |
Service name. |
|
string |
Action name. |
Responses#
Status |
Body |
Meaning |
|---|---|---|
|
— |
Action removed, or no such action existed. |
|
— |
Missing or invalid bearer token (auth enabled). |
|
error message (string) |
Caller lacks |
|
error message (string) |
Storage failure while deleting metadata. |
|
error message (string) |
Storage backend does not support writes. |
GET /v1beta/services/{service}/resource-types/ — list resource types#
Returns every resource type registered for the service.
Path parameters#
Name |
Type |
Description |
|---|---|---|
|
string |
Service name. |
Responses#
Status |
Body |
Meaning |
|---|---|---|
|
|
Resource types returned; empty array when none are registered. |
|
— |
Missing or invalid bearer token (auth enabled). |
|
error message (string) |
Caller lacks |
|
error message (string) |
Storage failure while reading metadata. |
|
error message (string) |
Storage backend does not support this operation. |
PUT /v1beta/services/{service}/resource-types/ — replace all resource types#
Replaces the complete set of resource types registered for the service. All existing resource types for {service} are deleted and replaced with the supplied list. The service field on every item in the body is overwritten with the URL path segment.
An empty array is accepted and clears all resource types for the service.
Path parameters#
Name |
Type |
Description |
|---|---|---|
|
string |
Service name. |
Request#
PUT /v1beta/services/storage-service/resource-types/ HTTP/1.1
Host: permission-service.storage-apis.svc.cluster.local:3000
Authorization: Bearer <token>
Content-Type: application/json
[
{ "type": "object", "evaluation_priority": "forbid" },
{ "type": "folder", "evaluation_priority": "permit" }
]
Responses#
Status |
Body |
Meaning |
|---|---|---|
|
— |
Resource types replaced. |
|
— |
Missing or invalid bearer token (auth enabled). |
|
error message (string) |
Caller lacks |
|
error message (string) |
JSON body failed to deserialize or an item had an invalid |
|
error message (string) |
Storage failure while writing metadata. |
|
error message (string) |
Storage backend does not support writes. |
GET /v1beta/services/{service}/resource-types/{type}/ — fetch resource type metadata#
Returns the ResourceTypeMeta for a single resource type.
Path parameters#
Name |
Type |
Description |
|---|---|---|
|
string |
Service name. |
|
string |
Resource type name. |
Responses#
Status |
Body |
Meaning |
|---|---|---|
|
|
Resource type found. |
|
— |
Missing or invalid bearer token (auth enabled). |
|
error message (string) |
Caller lacks |
|
error message (string) |
No resource type with that name is registered for this service. |
|
error message (string) |
Storage failure while reading metadata. |
|
error message (string) |
Storage backend does not support this operation. |
PUT /v1beta/services/{service}/resource-types/{type}/ — update resource type metadata#
Creates the resource type record if it does not exist, or updates it in place. The service and type fields of the payload are overwritten with the URL path segments, so the body effectively only needs to carry evaluation_priority.
Path parameters#
Name |
Type |
Description |
|---|---|---|
|
string |
Service name. |
|
string |
Resource type name. |
Request#
PUT /v1beta/services/storage-service/resource-types/object/ HTTP/1.1
Host: permission-service.storage-apis.svc.cluster.local:3000
Authorization: Bearer <token>
Content-Type: application/json
{
"evaluation_priority": "forbid"
}
Responses#
Status |
Body |
Meaning |
|---|---|---|
|
|
Metadata stored; the response echoes the record as persisted. |
|
— |
Missing or invalid bearer token (auth enabled). |
|
error message (string) |
Caller lacks |
|
error message (string) |
JSON body failed to deserialize or |
|
error message (string) |
Storage failure while writing metadata. |
|
error message (string) |
Storage backend does not support writes. |
DELETE /v1beta/services/{service}/resource-types/{type}/ — delete resource type metadata#
Removes a single resource type from the service.
Path parameters#
Name |
Type |
Description |
|---|---|---|
|
string |
Service name. |
|
string |
Resource type name. |
Responses#
Status |
Body |
Meaning |
|---|---|---|
|
— |
Resource type removed, or no such resource type existed. |
|
— |
Missing or invalid bearer token (auth enabled). |
|
error message (string) |
Caller lacks |
|
error message (string) |
Storage failure while deleting metadata. |
|
error message (string) |
Storage backend does not support writes. |
Evaluation priority for resources#
Each registered resource type carries an evaluation priority that controls how competing Cedar decisions are combined for requests targeting a resource of that type:
forbid(default) — if any matching policy evaluates toforbid, the request is denied. This is Cedar’s standard “deny overrides” behavior and is the safer default for resources where an explicit deny should always win.permit— if any matching policy evaluates topermit, the request is allowed, even when another policy evaluates toforbid. This is useful for resource types where permits are intended to be additive exceptions.
Evaluation priority only affects resource-scoped requests; requests with no resource follow the service-wide default. For a complete description of how priorities interact with policy scopes and Cedar decisions, see How authorization requests are evaluated.
idClaim for principals#
The id_claim field on a ServiceMeta record selects which claim from the caller’s bearer token is used as the principal id when the caller targets that service. When unset, the service falls back to the deployment-wide PRINCIPAL_ID_CLAIM (default sub). Different services in the same deployment can therefore identify the same user by different ids — for example, email for one service and sub for another.
For the full resolution order (per-service idClaim, deployment-wide PRINCIPAL_ID_CLAIM, sub fallback) and for the principal attributes this affects, see Principal in the Cedar policy guide.
Interactive API reference#
When the service runs with the REST API enabled, the full OpenAPI definition is served at /openapi.json and an interactive Swagger UI is available at /swagger-ui on the REST port (default 3000). Those surfaces stay in sync with the service implementation and cover every field and schema referenced on this page.
See also#
Writing Cedar policies for Permission Service — how
idClaimand resource types are referenced from policies.How authorization requests are evaluated — where
idClaimandevaluationPriorityare consumed in the evaluation pipeline.Managing policies through the REST API — companion API for the policies whose scopes reference these services, actions, and resource types.
Database configuration — metadata file format for config-file mode.
Deployment — seeding initial metadata through Helm.