Private betaRequest early access →

Sign in

Your own permissions — define them in Zynth, and let Zynth decide

Supported today. You can define your application's own authorization vocabulary in Zynth — resources, permissions and roles — and have Zynth answer "may this principal do this?" for your software. You do not need to build or run a parallel entitlements service alongside Zynth.

If you are evaluating Zynth and planning to keep your own authorization model because you assumed Zynth only knows about its own permissions, read this page first. That assumption is the most common one we see, and it is wrong.


How it fits together

  1. A resource — your application or API, bound one-to-one to an OAuth resource you have already registered. It supplies a namespace.
  2. Permissions — <namespace>:<action>, e.g. billing:invoices:void.
  3. Roles — your own roles, which can combine your permissions with Zynth's.
  4. Decisions — delivered two ways: as claims in an access token minted for your API, or live from the check API.

One engine answers everything. The same evaluator that enforces Zynth's own permissions decides yours. Assignments, delegations, attribute conditions and "why does this person have access" explanations all work on your permissions with no separate code path.

1. Register your resource

Register the OAuth resource first; an authorization resource binds to an audience Zynth already knows. Then:

Shell
curl -X POST https://auth.zynthmedia.com/api/v1/authz/resources \
  -H "Authorization: Bearer $ADMIN_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{
    "oauth_resource_id": "7c0e3f2a-…",
    "namespace": "billing",
    "description": "The billing API"
  }'

Returns 201 with resource_id and namespace.

RuleWhat happens
Namespace is 2–40 characters of a-z, 0-9 and -, starting with a letterOtherwise 422
Namespace may not be one of Zynth's own permission domains409 — your vocabulary can never collide with the platform's
The OAuth resource must exist422 — "register the OAuth resource first"
One OAuth resource ↔ one namespace409 if either is already bound

Who can do this: a human holding authz:resources:manage. An agent or an API key cannot define your authorization vocabulary, by design — the people who decide what a permission means are people.

2. Define permissions

Shell
curl -X POST https://auth.zynthmedia.com/api/v1/authz/resources/$RESOURCE_ID/permissions \
  -H "Authorization: Bearer $ADMIN_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{
    "action": "invoices:void",
    "description": "Void an issued invoice",
    "read_only": false,
    "risk": 12
  }'

This creates billing:invoices:void.

FieldMeaning
actionThe part after the namespace, 1–60 characters
read_onlyMarks a read. Reads and writes are treated differently in risk scoring and in agents' write budgets
risk1–15. Optional; defaults low for reads and higher for writes. Feeds risk-based decisions and review

List what you have with GET /api/v1/authz/resources (needs authz:resources:read).

3. Grant them through roles

Your permissions go into roles exactly like Zynth's own — the existing role API accepts them side by side. See Authorization admin for POST /api/v1/authz/roles.

From there the rest of Zynth's authorization applies unchanged: assignment to users, delegation to agents, attribute conditions, and the "why does this principal have access" explanation.

4. Ask Zynth to decide

Option A — read the claims in an access token (fast)

Mint an access token for your API (RFC 8707 resource), and it carries:

  • roles — the principal's role codes;
  • permissions — their effective permissions, filtered to your namespace.

Verify the token locally against Zynth's JWKS and read the claims. No network call per request.

Three rules to build against:

  • Past 96 permissions, the list is omitted — not shortened. The token then carries "permissions_truncated": true and no permissions list. A partial list would be a fail-open authorization statement, so Zynth never sends one. When you see the flag, ask the check API.
  • No vocabulary, no claims. A resource you have registered but not given permissions yields no roles or permissions at all. Nothing is invented.
  • Claims are as fresh as the token. A role change reaches the claims at the next refresh — up to the access token's lifetime (15 minutes by default). For a decision that must be current now, use the check API.

See verifying tokens → resource claims.

Option B — the check API (current, and batchable)

EndpointWho calls itAsks about
POST /api/v1/authz/checkAny principal, with its own tokenItself only — naming another principal answers 403
POST /api/v1/authz/service-checkYour resource server, with a client_credentials token carrying scope authz:checkAny principal in its tenant — a member, or an agent (answered from its delegations and oversight band)
Shell
curl -X POST https://auth.zynthmedia.com/api/v1/authz/service-check \
  -H "Authorization: Bearer $SERVICE_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{"checks": [
        {"permission": "billing:invoices:void", "principal_id": "3f9a…"}
      ]}'

Up to 50 checks per call (more answers 422). Each result:

JSON
{
  "principal_id": "3f9a…",
  "permission": "billing:invoices:void",
  "allowed": true,
  "via": "rbac",
  "reason": "…",
  "obligations": []
}

A check is a question, not an act: it changes nothing and charges nothing. Denials are recorded as security telemetry, and the endpoint is monitored as an enumeration surface — probing it for what a principal could do is itself a signal.

⚠️ allowed: true is not always "go"

If obligations is non-empty, treat the answer as "pending". An obligation such as human_approval means the action is permitted only once a human approves it — for example an agent under human-in-the-loop oversight. Zynth surfaces the obligation; it never resolves it inside a check. Proceed only when allowed is true and obligations is empty.

A resource server that reads allowed alone will proceed on actions that are still waiting for a human. See agent action approvals.

A check never parks an approval. To have Zynth decide an action and park a human approval for it — for an action your own executor performs — use the act endpoint, which takes one of the permissions you defined here: Approvals for actions Zynth does not execute.

5. Removing things

  • DELETE /api/v1/authz/resources/permissions/{permission_id} removes one permission.
  • DELETE /api/v1/authz/resources/{resource_id} removes a resource — and is refused with 409 while any role still grants one of its permissions. Remove it from the roles first. Zynth will not silently strip authority out of roles people are relying on.

What this is not

  • Not a billing meter. A permission can gate an action; it does not count usage. If you meter LLM tokens or spend, meter in your gateway and feed the verdict back as a permission — see Integrating an agent platform §5.
  • Not a second evaluator. There is no separate "customer authorization engine" to keep in step with Zynth's. Your permissions and Zynth's go through the same decision, the same audit trail and the same explanations.