REST API
The Permission Service exposes an HTTP/JSON API for checking authorization decisions. It provides two endpoints:
POST /v1beta/authorization/ – checks whether a principal is allowed to perform a single action on a resource;
POST /v1beta/authorization/batch/ – checks whether a principal is allowed to perform several actions in one request.
Both endpoints return HTTP 200 for any request that is evaluated; the authorization outcome is carried in the response body, not in the status code. Failures that prevent evaluation are reported with the error status codes listed in Error codes, whose body is always an ErrorString.
The key words “MUST”, “MUST NOT”, “REQUIRED”, “SHALL”, “SHALL NOT”, “SHOULD”, “SHOULD NOT”, “RECOMMENDED”, “MAY”, and “OPTIONAL” in this section are to be interpreted as described in RFC 2119.
Authentication
Callers SHOULD authenticate with the Authorization header in the Bearer <token> format. When authentication is enabled, the token MUST be a valid credential accepted by the service (by default a JWT issued by the Identity Provider for a user or a service). Requests with a missing, invalid, or expired token MUST be rejected with 401.
An implementation MAY support other authentication mechanisms (for example Basic Auth, API keys, or SAML2) and MAY change how authentication information is passed. When authentication is disabled, the service MAY process requests without credentials.
The underlying authorization system MAY allow a caller to check permissions for a principal different from the authenticated caller (for example an administrator checking another user). When this is not permitted, the service MUST reject the request with 403.
Error codes
The following status codes report failures that prevent a request from being evaluated. The response body for every error is an ErrorString.
Request and response models
AuthorizationPayload
Request body of POST /v1beta/authorization/.
AuthorizationResponse
Result of a single authorization check. No fields other than those below are permitted.
AuthorizationBatchRequest
Request body of POST /v1beta/authorization/batch/.
AuthorizationBatchResponse
Result of a batch authorization check.
ErrorString
The body of every error response is a plain JSON string (not an object). Max 2048 characters; pattern ^[\x20-\x7E\r\n]+$. For example:
"The principal token is expired."
POST /v1beta/authorization/ — Check a single permission
Checks whether the specified principal is allowed to perform an action on a resource.
Request body: AuthorizationPayload.
The service returns 200 with an AuthorizationResponse: allow when a rule matches, otherwise deny. An explicit denial SHOULD populate reason; an implicit denial (no matching rule) SHOULD omit it. When present, action and service MUST echo the request values.
The context field is OPTIONAL and MAY be omitted; an implementation MAY ignore it or use it during evaluation.
Request example:
POST /v1beta/authorization/ HTTP/1.1
Authorization: Bearer eyJraWQiOiJvYXV0aC1zaWduL[...]cc5IgUXhY66ML-CZVlRw
Content-Type: application/json
{
"principal": {
"sub": "DdxA9xDiqdUbv",
"info": {"email": "user@test.com", "exp": 1727821346329}
},
"action": {
"name": "read",
"service": "storage"
},
"resource": {
"id": "/Projects/Scene.usd",
"type": "File",
"data": {
"metadata": {"size": 1024}
}
},
"context": {
"ip": "127.0.0.1",
"location": {"lat": 54.32, "lon": 33.44}
}
}
The principal field MAY be omitted when it matches the authenticated token payload:
POST /v1beta/authorization/ HTTP/1.1
Authorization: Bearer eyJraWQiOiJvYXV0aC1zaWduL[...]cc5IgUXhY66ML-CZVlRw
Content-Type: application/json
{
"action": {
"name": "download",
"service": "storage"
},
"resource": {
"id": "/Projects/Scene.usd",
"type": "File"
}
}
Allow response:
HTTP/1.1 200 OK
Content-Type: application/json
{
"decision": "allow",
"action": "read",
"service": "storage"
}
Explicit deny response:
HTTP/1.1 200 OK
Content-Type: application/json
{
"decision": "deny",
"reason": "No rule grants read on this resource.",
"action": "read",
"service": "storage"
}
POST /v1beta/authorization/batch/ — Check permissions in batch
Batched variant of POST /v1beta/authorization/ that evaluates multiple actions, resources, and principals in one request.
Request body: AuthorizationBatchRequest.
Instead of repeating the same resource, a client SHOULD list all actions to check for a resource in a single batch entry. Each principal MAY be omitted when it matches the authenticated token payload.
The service returns 200 with an AuthorizationBatchResponse. The decisions array contains exactly one object per request batch, in order; each object has one <service>:<action> key for each distinct action in that batch’s actions array.
Actions are evaluated across all batches in request order (all actions in batch 0, then batch 1, and so on). The condition field controls short-circuiting, which spans all batches, and whether a summary is produced:
none (default) – Every action in every batch is evaluated independently, as if sent as separate requests. No action is skip, and summary MUST be omitted.
and – Evaluation stops after the first deny. Remaining unevaluated actions (including actions in later batches) are set to skip. summary.decision is deny if any action was denied, otherwise allow. summary MUST be present.
or – Evaluation stops after the first allow. Remaining unevaluated actions (including actions in later batches) are set to skip. summary.decision is allow if any action was allowed, otherwise deny. summary MUST be present.
Examples
Check several actions for one resource, evaluated independently (none):
POST /v1beta/authorization/batch/ HTTP/1.1
Authorization: Bearer eyJraWQiOiJvYXV0aC1zaWduL[...]cc5IgUXhY66ML-CZVlRw
Content-Type: application/json
{
"batches": [
{
"principal": {"sub": "DdxA9xDiqdUbv", "info": {"email": "user@test.com"}},
"actions": [
{"name": "read", "service": "storage"},
{"name": "write", "service": "storage"},
{"name": "set", "service": "tags"},
{"name": "get", "service": "tags"}
],
"resource": {
"id": "/Projects/Scene.usd",
"type": "File",
"data": {"metadata": {"size": 1024}}
}
}
]
}
Response:
HTTP/1.1 200 OK
Content-Type: application/json
{
"decisions": [
{
"storage:read": {"decision": "allow"},
"storage:write": {"decision": "deny"},
"tags:set": {"decision": "deny", "reason": "No matching rule."},
"tags:get": {"decision": "allow"}
}
]
}
Check whether the caller has storage:read on any of several resources (or):
POST /v1beta/authorization/batch/ HTTP/1.1
Authorization: Bearer eyJraWQiOiJvYXV0aC1zaWduL[...]cc5IgUXhY66ML-CZVlRw
Content-Type: application/json
{
"condition": "or",
"batches": [
{
"actions": [{"name": "read", "service": "storage"}],
"resource": {"id": "/Projects/Astronaut/Astronaut.usd", "type": "File"}
},
{
"actions": [{"name": "read", "service": "storage"}],
"resource": {"id": "/Projects/Marbles/Marbles_Assets.usd", "type": "File"}
}
]
}
Response:
HTTP/1.1 200 OK
Content-Type: application/json
{
"summary": {"decision": "allow"},
"decisions": [
{"storage:read": {"decision": "allow"}},
{"storage:read": {"decision": "skip"}}
]
}
Check whether the caller has every listed action on a resource (and):
POST /v1beta/authorization/batch/ HTTP/1.1
Authorization: Bearer eyJraWQiOiJvYXV0aC1zaWduL[...]cc5IgUXhY66ML-CZVlRw
Content-Type: application/json
{
"condition": "and",
"batches": [
{
"actions": [
{"name": "read", "service": "storage"},
{"name": "write", "service": "storage"},
{"name": "set", "service": "tags"},
{"name": "get", "service": "tags"}
],
"resource": {
"id": "/Projects/Scene.usd",
"type": "File",
"data": {"metadata": {"size": 1024}}
}
}
]
}
Response:
HTTP/1.1 200 OK
Content-Type: application/json
{
"summary": {"decision": "deny"},
"decisions": [
{
"storage:read": {"decision": "allow"},
"storage:write": {"decision": "deny"},
"tags:set": {"decision": "skip"},
"tags:get": {"decision": "skip"}
}
]
}