Skip to main content

Permissions

Permissions define specific abilities in your application. Every permission follows the resource:action format and belongs to a single application. Permissions are attached to roles, and users inherit permissions through their assigned roles.

Permission Format

All permissions use the resource:action format:

text
posts:create
users:delete
reports:export
billing:view

Wildcards (*) are also valid in either position:

text
posts:*      # all actions on posts
*:read       # read action on any resource
*:*          # all actions on all resources (full access)

See Wildcard Matching for full pattern rules.

Validation pattern: ^[a-zA-Z0-9_*-]+:[a-zA-Z0-9_*-]+$

Permissions are created automatically when you use them in a role. You do not need to pre-register them before attaching to a role.

Defining Permissions

Permissions are defined inline when creating or updating roles — there is no standalone permission creation endpoint in the V1 API. When you include a permission string in a role's permissions array, it is created automatically if it does not already exist.

json
{
  "name": "editor",
  "permissions": ["posts:create", "posts:edit", "reports:export"]
}

See the Roles API for how to create roles and assign permissions.

Full permission management (list, create, update, delete) is available via the Dashboard API at /api/dashboard/applications/{applicationId}/permissions. These endpoints use Sanctum cookie authentication and are intended for use by the YorAuth dashboard.

Check a Permission

The primary authorization check endpoint. Use this on your backend to gate any action.

text
GET  /api/v1/applications/{applicationId}/authz/check
POST /api/v1/applications/{applicationId}/authz/check

Requires JWT scope: authz:check

Use GET for simple RBAC-only checks (pass parameters as query string). Use POST when you need to include resource or context attributes for ABAC policy evaluation.

RBAC-only check (GET)

bash
curl -X GET \
  "https://api.yorauth.com/api/v1/applications/your-application-id/authz/check?user_id=user-123&permission=posts:create" \
  -H "Authorization: Bearer <jwt>"

Response 200 OK:

json
{
  "allowed": true,
  "permission": "posts:create",
  "cached": true
}

The cached field indicates whether the result was served from Redis. A cached result typically adds under 5ms of latency.

RBAC + ABAC check (POST)

When you pass resource or context, the authorization engine runs RBAC first. If RBAC denies, it returns immediately. If RBAC allows, active ABAC policies for the permission are evaluated.

bash
curl -X POST \
  https://api.yorauth.com/api/v1/applications/your-application-id/authz/check \
  -H "Authorization: Bearer <jwt>" \
  -H "Content-Type: application/json" \
  -d '{
    "user_id": "user-123",
    "permission": "posts:delete",
    "resource": {
      "owner_id": "user-123",
      "status": "draft"
    },
    "context": {
      "ip": "203.0.113.42"
    }
  }'

Response 200 OK (with ABAC):

json
{
  "allowed": true,
  "permission": "posts:delete",
  "cached": false,
  "abac_evaluated": true,
  "policies_checked": 2
}

Request parameters:

ParameterRequiredDescription
user_idYesYour external user identifier
permissionYesPermission string in resource:action format
resourceNoKey-value map of resource attributes for ABAC
contextNoKey-value map of context attributes for ABAC (IP, time, etc.)

Response fields:

FieldDescription
allowedtrue if the user has the permission
permissionThe permission that was checked
cachedWhether the RBAC result came from Redis cache
abac_evaluatedPresent when ABAC params provided; true if policies were evaluated
policies_checkedNumber of ABAC policies evaluated (present with ABAC params)

Error responses:

  • 422 Unprocessable Entity — Invalid permission format (must match resource:action)

Bulk Permission Check

Check up to 50 permissions for a user in a single request.

text
POST /api/v1/applications/{applicationId}/authz/check-bulk

Requires JWT scope: authz:check

The user's permission set is loaded once from cache and all checks are evaluated in memory — this is more efficient than making multiple single-check requests.

bash
curl -X POST \
  https://api.yorauth.com/api/v1/applications/your-application-id/authz/check-bulk \
  -H "Authorization: Bearer <jwt>" \
  -H "Content-Type: application/json" \
  -d '{
    "user_id": "user-123",
    "permissions": [
      "posts:create",
      "posts:delete",
      "users:invite",
      "billing:view",
      "reports:export"
    ]
  }'
javascript
const response = await fetch(
  'https://api.yorauth.com/api/v1/applications/your-application-id/authz/check-bulk',
  {
    method: 'POST',
    headers: {
      'Authorization': 'Bearer <jwt>',
      'Content-Type': 'application/json'
    },
    body: JSON.stringify({
      user_id: 'user-123',
      permissions: [
        'posts:create',
        'posts:delete',
        'users:invite',
        'billing:view',
        'reports:export'
      ]
    })
  }
);
const { user_id, results } = await response.json();

Response 200 OK:

json
{
  "user_id": "user-123",
  "results": {
    "posts:create": true,
    "posts:delete": true,
    "users:invite": false,
    "billing:view": false,
    "reports:export": true
  }
}

Bulk check with ABAC

You can also pass resource and context to the bulk endpoint. When provided, each permission that passes RBAC is additionally evaluated through active ABAC policies. The result per permission is a boolean.

json
{
  "user_id": "user-123",
  "permissions": ["posts:delete", "posts:publish"],
  "resource": { "owner_id": "user-123", "status": "draft" },
  "context": { "ip": "203.0.113.42" }
}

Request parameters:

ParameterRequiredDescription
user_idYesYour external user identifier
permissionsYesArray of 1–50 permission strings
resourceNoKey-value map of resource attributes for ABAC
contextNoKey-value map of context attributes for ABAC

The bulk check uses a single Redis lookup to load the user's permission set, then evaluates all permissions in memory. Use it when you need to determine multiple access decisions at once — such as rendering a UI with enabled/disabled actions.

Caching Behaviour

Permission checks are backed by versioned Redis caching. The user's complete permission set (all permissions from all roles, including team-inherited ones) is cached for 1 hour.

When any of the following happen, the cache version is incremented, making all cached permission sets for the application immediately stale:

  • A role is created, updated, or deleted
  • A permission is assigned to or removed from a role
  • A user's role assignment is added or revoked

On the next check after invalidation, the permission set is recomputed from the database and re-cached.

The cached field in a single-check response reflects whether the current check hit the cache or required a database query.