Authaz logoAuthaz
DocumentationAPI Reference
  • Get Started

    • Authaz
    • Core Concepts
    • Set up your app
    • Quickstart — cURL
  • Authentication

    • Authentication Settings
    • Signup
    • Invitations
    • Password Authentication
    • Multi-Factor Auth
    • Magic Link
    • OAuth / Social Login
    • Passkey (WebAuthn)
    • SAML SSO
    • Machine-to-Machine (M2M)
    • API Keys
  • Authorization

    • Authorization
    • Resources
    • Policies
    • Roles
    • Access Explorer
  • Tenancy

    • Multi-tenancy
    • Tenancy Customization
  • Brand & Host

    • Branding
    • Custom Domains
    • Communications & Email Templates
  • Operate

    • Users
    • Analytics
    • Audit Logs
    • Application Settings
  • SDK Quickstarts

    • Quickstart — Next.js
    • Quickstart — React SPA
    • Quickstart — Hono
    • Quickstart — .NET (Authaz.Sdk)
  • Recipes

    • Recipes & Cookbook
    • Next.js — first integration
    • Next.js — B2B SaaS (multi-tenant)
    • Hono — first integration
    • Hono — B2B SaaS (multi-tenant)
    • React SPA — first integration
    • React SPA — B2B SaaS (multi-tenant)
    • .NET — first integration
    • .NET — B2B SaaS (multi-tenant)
  • Reference

    • Tokens
    • API Reference
    • Errors & Troubleshooting
  • Documentation

    • How Authaz is Built
  1. Authaz
  2. Docs
  3. Authorization
  4. Resources

Authorization

Resources

3 min read·Updated Jun 19, 2026

The Resource Catalog (under Authorization → Manage → Resources) is where you declare every thing in your application that has permissions attached. Roles and policies can only reference permissions that exist here — the catalog is the source of truth.

# Define a resource
curl -X PUT https://your-app.authaz.io/api/v1/applications/{appId}/resources \
  -H "X-API-Key: $AUTHAZ_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "resources": [
      {
        "resource": "invoices",
        "description": "Customer invoices and billing records.",
        "actions": ["create", "read", "update", "delete", "send", "archive"]
      },
      {
        "resource": "customers",
        "description": "Customer records.",
        "actions": ["create", "read", "update", "delete"]
      }
    ]
  }'

Resource names + actions become permission strings: invoices:create, customers:read, etc. The dashboard's resource editor previews these as you type.

Previous
Authorization
Next
Policies

Where it lives#

Dashboard → Application → Authorization → Resources. The page shows every resource with its actions in an editable table. A counter at the top tells you the total — a sane catalog usually has 5–20 resources.

What goes in a resource#

FieldWhat it is
resource (key)A short, stable identifier in lower-snake-case: users, invoices, api_keys. Don't change this casually — it's referenced from every policy.
descriptionHuman-readable. Shows in the policy editor when picking permissions.
actionsThe verbs valid for this resource: read, update, delete, etc. Each action becomes a permission resource:action.

The dashboard helps with action names — common ones (create, read, update, delete, list) auto-complete. Custom actions (invoices:send, users:invite) are fine; just keep them short and verb-shaped.

Modelling tips#

Granularity. One resource per concept, not per database table. If "invoices" and "invoice_line_items" are always touched together, they're one resource as far as authorization is concerned.

Actions. Stick to a small standard vocabulary plus the few domain verbs that genuinely matter:

create  read  update  delete  list      ← the standard CRUD-ish set
send    archive  publish  approve  invite  ← verbs your business cares about

If you find yourself adding update_status_to_pending, update_status_to_approved, etc., collapse them — the action is update; the which-status-is-allowed logic belongs in your business code.

Naming. resource:action strings show up in audit logs, error messages, JWT claims, and permission checks. They're load-bearing identifiers — pick names you won't want to refactor.

Direct resource grants (ReBAC)#

For "this user can read this specific document" cases, skip roles and grant directly on a resource instance:

curl -X POST https://your-app.authaz.io/api/v1/authorization/relationships \
  -H "X-API-Key: $AUTHAZ_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "userId": "user_01h...",
    "resource": "documents",
    "resourceId": "doc_01h...",
    "relation": "viewer"
  }'

Now this user can do anything viewer allows on doc_01h..., and only on that document. The check:

curl -X POST https://your-app.authaz.io/api/v1/authorization/check \
  -H "X-API-Key: $AUTHAZ_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "userId": "user_01h...",
    "resource": "documents",
    "resourceId": "doc_01h...",
    "action": "read"
  }'

Returns { "allowed": true } even if the user has no roles in this application.

Relations#

A relation is the named connection between a user and a resource. Authaz ships with a small set of built-in relations:

RelationAllowed actions (default)
ownerevery action on this resource type
editorcreate, read, update
viewerread, list
commenterread, comment (if comment is a valid action)

You can define custom relations per resource — the catalog editor has a Relations tab where each relation picks which actions it implies. Keep this small; most apps need 2–3 relations max.

Listing relationships#

# Everyone with a relation on a resource
curl 'https://your-app.authaz.io/api/v1/authorization/relationships?resource=documents&resourceId=doc_01h...' \
  -H "X-API-Key: $AUTHAZ_API_KEY"
 
# Every resource a user has a relation on
curl 'https://your-app.authaz.io/api/v1/authorization/relationships?userId=user_01h...&resource=documents' \
  -H "X-API-Key: $AUTHAZ_API_KEY"

The dashboard's Access Explorer surfaces both views interactively — useful when investigating "why can this person see this thing?".

Bulk writes#

For migrating an existing app to Authaz, batch the writes:

curl -X POST https://your-app.authaz.io/api/v1/authorization/relationships/bulk \
  -H "X-API-Key: $AUTHAZ_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "writes": [
      { "userId": "u1", "resource": "documents", "resourceId": "d1", "relation": "owner"  },
      { "userId": "u1", "resource": "documents", "resourceId": "d2", "relation": "editor" },
      { "userId": "u2", "resource": "documents", "resourceId": "d1", "relation": "viewer" }
    ]
  }'

Up to 5,000 writes per call.

When to use each style#

SituationRoles + PoliciesDirect grants (ReBAC)
User-type-based access ("Admins can do X")✓
Per-record access ("Alice can see this one document")✓
Same access for everyone in a tenant✓
Sharing UI ("Invite people to this project")✓
Role hierarchies that change rarely✓
Heavy mutation (millions of grants)✓ (Zeratul is built for this)

Use both. Most real apps start role-based, then add direct grants when a sharing/collaboration feature lands.

Next steps#

  • Policies — bundles built from the actions you defined here.
  • Roles — composed from those policies.
  • Access Explorer — debug a check and see whether the answer came from a role or a direct grant.