Skip to content

Permission Evaluation Benchmarks

Summary of permission evaluation performance via POST /api/auth/is-authorized — the path SDKs and app guards use on every authorized request. Raw dated dumps from pnpm benchmark:authz stay local; this page is the committed report.

Dashboard GraphQL list queries are out of scope here; see Field Selection for UI payload shape guidance.

Environment

FieldValue
Date2026-07-20
APILocal (http://localhost:4000)
ScopeaccountProject (CDM-imported project with ~371 permissions, ~272 users)
EndpointPOST /api/auth/is-authorized
Runs per check20
Throughput30 cold checks, concurrency 3

Cold runs vary context.resource.id so each call bypasses the AuthHandler result cache and exercises real evaluation. Warm runs reuse a fixed context after a prime request (cache hit).

Results

Checkmodep50 (ms)p95 (ms)minmaxmeanauthorizedreasonokTarget
allow: Project.Querycold1123104014truePERMISSION_GRANTED_NO_CONDITIONyesPass (p95 < 50ms)
allow: Project.Querywarm45495truePERMISSION_GRANTED_NO_CONDITIONyesPass (p95 < 15ms)
allow: Permission.Querycold91291310truePERMISSION_GRANTED_NO_CONDITIONyesPass
allow: Permission.Querywarm48485truePERMISSION_GRANTED_NO_CONDITIONyesPass
allow: Role.Querycold91091310truePERMISSION_GRANTED_NO_CONDITIONyesPass
allow: Role.Querywarm46485truePERMISSION_GRANTED_NO_CONDITIONyesPass
deny: unknown resourcecold9139139falseNO_MATCHING_PERMISSION_FOUNDyesPass
deny: unknown resourcewarm45494falseNO_MATCHING_PERMISSION_FOUNDyesPass
deny: ungranted CDM actioncold101391711falseNO_MATCHING_PERMISSION_FOUNDyesPass
deny: ungranted CDM actionwarm45484falseNO_MATCHING_PERMISSION_FOUNDyesPass

Throughput

Checktotalconcurrencywall (ms)checks/sp50p95ok
allow: Project.Query (cold)3031921561634yes

Targets

  • Cold evaluation p95 < 50ms
  • Warm (cached) p95 < 15ms
  • Allow/deny outcomes match expectations
  • Zero HTTP errors

All checks met these targets on this run.

Interpretation

What is being measured

Each call unions permission sources for the caller in scope (role→group, user→group, role→permission, user→permission), matches action + resource, then evaluates conditions when present. See Architecture Overview → Permission Evaluation.

ModeMeaning
ColdCache-busted evaluation — closest to “first check” cost after deploy or for a new resource context
WarmAuthHandler cache hit — typical repeat check for the same permission + context within the token TTL
ThroughputBounded-concurrency cold checks — rough sustained capacity under light parallel load

Allow vs deny

Deny paths (NO_MATCHING_PERMISSION_FOUND) are as fast as allow on this dataset — the engine still collects and filters permission IDs; absence of a match is not a cheap short-circuit before that work. That is the right property for security; it also means deny traffic is not “free.”

Cache effect

Warm p95 (~5–8ms) is roughly 2–4× faster than cold p95 (~10–23ms). Integrations that re-check the same permission+context benefit from the server-side authorization cache automatically.

Takeaways

  • Permission evaluation stays well under 50ms p95 cold for this project size.
  • Cached checks are single-digit milliseconds.
  • ~150 cold checks/s at concurrency 3 on a local API is a useful floor for capacity planning (staging/production will differ with hardware and pool size).
  • Avoid unbounded parallel fan-out against is-authorized from a single client; use modest concurrency (the benchmark defaults to 3).

How to reproduce

bash
pnpm benchmark:authz -- --base-url http://localhost:4000 --runs 20
# alias: pnpm benchmark:rbac

Optional flags:

  • --throughput 30 — total cold checks in the throughput phase (0 to skip)
  • --concurrency 3 — max in-flight requests during throughput

Optional env:

  • GRANT_API_BASE_URL — API base URL
  • GRANT_BENCHMARK_CREDENTIALS — path to API key credentials JSON (clientId, clientSecret, scope)

Credentials may include a custom checks array (name, permission, expectAuthorized) to override the defaults.

Script: scripts/benchmarks/permission-evaluation.mjs. Fresh dated JSON/MD files are written under docs/benchmarks/ as authz-{date}.* (gitignored except this report and the README).

Released under the MIT License.