Arke
Understand

Permissions & Authorization

How authentication, authorization, and permissions work in Arke -- JWT auth, API keys (user vs agent), collections, roles, temporal permissions, and the permission resolution flow.

Authentication

Arke supports three authentication methods, each suited to different use cases.

JWT (JSON Web Tokens)

Users authenticate through Supabase for web sessions. The gateway validates the JWT and extracts user identity.

Authorization: Bearer eyJhbGciOiJIUzI1NiIs...

JWT auth provides access to user-specific claims (email, name, Supabase ID) and is typically used for browser-based applications.

User API Keys (uk_)

User API keys provide programmatic access for SDKs, CLIs, and CI/CD pipelines. They authenticate as the user with the same permissions.

Authorization: ApiKey uk_a1b2c3d4e5f6...
PropertyValue
Prefixuk_
Default expiry90 days
Maximum expiry365 days
Use casesSDK, CLI, automation, CI/CD

User keys are managed via /auth/api-keys endpoints.

Agent API Keys (ak_)

Agent API keys authenticate external services (agents) that process entities on behalf of users. They authenticate as the agent, not the user.

Authorization: ApiKey ak_x9y8z7w6v5u4...
PropertyValue
Prefixak_
Default expiry365 days
Use casesExternal processing services, webhooks
Owner trackingEach agent has an owner_pi (the user who controls it)

Agent keys are managed via /agents/{id}/api-keys endpoints.

Key Differences: User Keys vs Agent Keys

AspectUser Key (uk_)Agent Key (ak_)
Authenticates asUser entityAgent entity
PermissionsUser's own permissionsPermissions granted to the agent
Actor typeuseragent
Owner fieldN/AownerPi (controlling user)
Audit trailActions logged as userActions logged as agent + owner

Permission Resolution

When a request is made, Arke determines permissions through a specific resolution order.

Resolution Flow

1. Self-ownership check (users can view/update themselves)

2. Parent collection lookup (find entity's collection)

3. Role resolution (find actor's role in collection)

4. Action check (does role allow the action?)

5. Open season fallback (no collection = public access)

Resolution Methods

MethodWhen It AppliesResult
selfUser accessing their own user entityGrants user:view, user:update
collectionEntity belongs to a collectionPermissions based on actor's role
open_seasonEntity has no parent collectionPublic read access (with restrictions)

Special Rules

User updates require explicit permission. Unlike other entities, user:update is never granted via open season. Users can only be modified by:

  • The user themselves (self-ownership)
  • Someone with explicit permission in a collection containing the user

Deleted collections hide their contents. When a collection is soft-deleted, all entities inside become inaccessible. The only exception: the user who deleted the collection can restore it via collection:restore.


Collections as Permission Boundaries

Every entity can belong to a collection. Collections define roles (named permission sets) and assign those roles to users.

How Collections Work

  1. A collection defines roles with specific allowed actions
  2. Users are assigned roles via relationships on the collection
  3. When accessing an entity, Arke finds its parent collection
  4. Arke looks up the actor's role in that collection
  5. The role's actions determine what's allowed

Default Roles

New collections include these roles by default:

RoleActionsPurpose
owner*:view, *:update, *:create, collection:update, collection:manageFull control including settings
editor*:view, *:update, *:createModify entities, no settings access
viewer*:viewRead-only access
public*:viewWildcard assignment for anonymous users

Role Resolution Priority

When determining an actor's role:

  1. Direct assignment (highest priority): Actor is explicitly assigned a role
  2. Group membership (future): Actor belongs to a group with a role
  3. Wildcard assignment (lowest priority): Role assigned to * (everyone)
collection.relationships:
  - predicate: "owner", peer: "01JUSER123...", peer_type: "user"    → Direct
  - predicate: "viewer", peer: "*", peer_type: "wildcard"           → Wildcard

Permission Actions

Actions follow the resource:verb pattern. This creates a structured permission model.

Action Format

<resource>:<verb>

Examples:

  • entity:view -- View any entity
  • file:update -- Update file entities
  • collection:manage -- Manage collection membership

Registered Actions

ActionDescription
entity:viewRead entity content
entity:updateModify existing entity
entity:createCreate new entities
entity:deleteSoft-delete entity
file:viewView file metadata
file:updateUpdate file content
file:downloadAccess original file binary
collection:viewView collection
collection:updateModify collection settings
collection:manageManage roles and membership
collection:deleteDelete collection
collection:restoreRestore deleted collection
user:viewView user profile
user:updateModify user profile

Wildcards

Wildcards allow granting broad permissions efficiently.

Verb wildcards match any resource type:

*:view    → Matches entity:view, file:view, user:view, etc.
*:update  → Matches entity:update, file:update, user:update, etc.

Type wildcards match any verb for a type:

file:*    → Matches file:view, file:update, file:download
entity:*  → Matches entity:view, entity:update, entity:create, entity:delete

Type Implications

Entity types form a hierarchy. Granting a parent type implies child types:

entity:view  → implies file:view, user:view, collection:view, etc.
entity:*     → implies file:*, user:*, etc.

This means *:view on the owner role grants view access to all entity types.

Verb Implications

Some verbs imply others:

  • view implies download (if you can view a file, you can download it)

Action Mapping for Collections

When checking permissions on a collection itself, entity actions map to collection actions:

RequestEffective Check
entity:view on collectioncollection:view
entity:update on collectioncollection:update
entity:delete on collectioncollection:delete

Note: entity:create is NOT mapped -- it means "create entities inside this collection."


Temporal Permissions

Role assignments can include expiration times for automatic revocation.

How It Works

Role assignments are stored as relationships with optional temporal properties:

{
  "predicate": "editor",
  "peer": "01JUSER789...",
  "peer_type": "user",
  "properties": {
    "expires_at": "2025-06-01T00:00:00.000Z",
    "granted_at": "2025-01-01T12:00:00.000Z",
    "granted_by": "01JUSER123..."
  }
}

Temporal Properties

PropertyDescription
expires_atISO 8601 timestamp when access expires (omit for permanent)
granted_atWhen the role was assigned
granted_byWho assigned the role

Behavior

  • Expired relationships are skipped during role resolution
  • Invalid date formats are treated as permanent (to avoid lockouts)
  • No background job required -- expiry is checked at query time

Agent Authorization

Agents (external processing services) have a specialized permission model.

How Agents Work

  1. Agents are entities of type agent with API keys
  2. Each agent has an owner (the user who controls it)
  3. Agents declare what permissions they need (actions_required)
  4. Users grant agents access to specific collections

Agent Permission Flow

Agent authenticates (ak_ key)

Request includes target entity

Find entity's collection

Check if agent has role in collection

Verify role allows requested action

Request Signing

When Arke invokes agents, it signs the request with Ed25519:

X-Arke-Signature: <signature>
X-Arke-Timestamp: <unix-timestamp>

Agents should verify this signature to ensure requests originate from Arke.

Audit Trail

Agent actions are logged with both identities:

  • edited_by.agent: The agent that performed the action
  • edited_by.agent_owner: The user who owns the agent

Permission API

You can query permissions programmatically.

Get Permission System Metadata

GET /permissions

Returns all registered actions, verbs, types, implications, and default roles. This endpoint requires no authentication and is useful for building dynamic role editors or validating actions client-side.

{
  "actions": ["collection:delete", "collection:manage", "collection:restore", "collection:update", "collection:view", "entity:create", "entity:delete", "entity:update", "entity:view", "file:download", "file:reupload", "file:update", "file:view", "user:update", "user:view"],
  "verbs": ["create", "delete", "download", "manage", "restore", "reupload", "update", "view"],
  "types": ["collection", "entity", "file", "user"],
  "implications": {
    "view": ["download"]
  },
  "type_hierarchy": {
    "base_type": "entity",
    "description": "Actions with type 'entity' imply the same action for all specific types.",
    "restrictions": [...]
  },
  "wildcards": {
    "verb": { "pattern": "*:{verb}", "example": "*:view", "description": "..." },
    "type": { "pattern": "{type}:*", "example": "file:*", "description": "..." }
  },
  "restrictions": [
    "collection:* is not allowed - use explicit collection actions for security",
    "*:update does not match collection:update - collection operations require explicit permission",
    ...
  ],
  "default_roles": {
    "owner": ["*:view", "*:update", "*:create", "collection:update", "collection:manage"],
    "editor": ["*:view", "*:update", "*:create"],
    "viewer": ["*:view"],
    "public": ["*:view"]
  }
}

Check Entity Permissions

GET /entities/{id}/permissions

Returns:

{
  "entity_id": "01JFILE123...",
  "entity_type": "file",
  "allowed_actions": ["entity:view", "file:view", "file:download"],
  "resolution": {
    "method": "collection",
    "collection_id": "01JCOLL456...",
    "role": "viewer"
  }
}

Resolution Methods in Response

MethodMeaning
collectionPermissions came from a role in a collection
selfUser accessing their own entity
open_seasonEntity has no collection (public access)

If resolution.deleted is true, the collection was soft-deleted and the entity is inaccessible.

On this page