Benchmarks

Numbers you can rerun

The TypeScript policy engine does 2.45M warm-cache evaluations per second on one core, with a p99 of 625 ns. Everything below was measured on the machine, versions and commits listed, on 2026-10-07.

Run details

This run2026-10-07

Machine

CPU
Apple M4 Max, 14 cores, 36 GB memory
OS
macOS 26.2

TypeScript

Runtime
Node v22.22.2, vitest 3.2.4
Commit
d83c019, 5 runs, medians shown

Go

Toolchain
go1.26.5
Commit
7b0fd43, medians across runs

TypeScript

Policy engine

One user, one agent and five permissions in an in-memory SQLite database, audit logging off. Warm means a pre-warmed cache hit. Cold means the cache is invalidated before every call, so each evaluation pays one database round trip. The range column is the lowest and highest run, so you can see how noisy the machine was.

TypeScript policy engine benchmark results
ScenarioEvaluations per secondRange across runsp99 latencyp99 range
warm cache hit2.45M2.41M to 2.51M625 ns583 ns to 625 ns
cold path - direct permission10.2k10.1k to 10.9k189 µs187 µs to 206 µs
cold path - rbac role expansion22.0k20.7k to 22.4k73.0 µs67.8 µs to 77.4 µs
cold path - rebac graph lookup6.4k6.1k to 6.7k356 µs297 µs to 375 µs

Go

Hot paths in theauth-go

The twelve benchmarks that gate every release against regressions, in memory storage. Argon2 runs at the production work factor, so those two rows are slow on purpose. Times are per operation.

Go hot path benchmark results
BenchmarkWhat it measuresTime per opRange across runsMemory per opAllocations per op
BenchmarkArgon2HashArgon2id hash at the production work factor.26.4 ms25.9 ms to 27.1 ms64.0 MiB86
BenchmarkArgon2VerifyArgon2id verify at the production work factor.26.3 ms26.2 ms to 26.8 ms64.0 MiB88
BenchmarkAuditRedactorAudit redactor key matching.689 ns669 ns to 714 ns0.7 KiB4
BenchmarkOAuthCallbackSocial-provider callback: AES-GCM encrypt and in-memory upsert.813 ns788 ns to 843 ns1.3 KiB5
BenchmarkOAuthCodeFlowAuthorization code grant: PKCE S256 check, code consume, JWT mint, refresh insert.24.1 µs23.8 µs to 24.4 µs16.5 KiB106
BenchmarkOAuthTokenEndpointRefreshHitRefresh-token grant on /oauth/token with the client-secret Argon2 cache warm.24.1 µs23.7 µs to 24.5 µs16.2 KiB106
BenchmarkJWKSEndpointJWKS endpoint: signing-key snapshot read and JSON marshal.3.49 µs3.46 µs to 3.58 µs3.5 KiB42
BenchmarkSCIMTokenAuthSCIM bearer authentication: SHA-256 hash plus one storage lookup.7.25 µs7.16 µs to 7.55 µs10.4 KiB60
BenchmarkSessionLookupCookie parse, token hash and in-memory lookup: the floor cost of an authenticated request.4.34 µs4.16 µs to 8.87 µs9.1 KiB46
BenchmarkJWTSignEd25519 JWT sign.15.7 µs15.5 µs to 19.1 µs2.8 KiB15
BenchmarkJWTVerifyEd25519 JWT verify.36.1 µs34.9 µs to 37.8 µs3.4 KiB61
BenchmarkRateLimitReadHeavyRate limiter under parallel, read-heavy load.129 ns116 ns to 131 ns0.0 KiB0

What these numbers do not cover

  • Network and TLS. Every benchmark runs in process.
  • Real databases. Storage is in memory (SQLite in memory for TypeScript). Postgres and MySQL add round trips these results do not include.
  • Scaling across cores. The TypeScript engine is single-threaded here. Go has one parallel case, the rate limiter.
  • Large policy sets. The TypeScript run uses five permissions. Cold-path cost grows with the policy graph.
  • Audit logging, memory use and cold start. Audit is off in the TypeScript run, and neither run measures process memory or startup time.
  • Other libraries. We publish our own numbers only. A fair comparison needs the same harness and hardware for every library, and we have not built that.

Results move with the machine. A laptop running other work gives noisier and slower numbers, which is why the range columns exist. Treat the figures as a baseline for your own hardware, not a promise.

Reproduce

Two commands

Both repositories are public. Clone, install, run. The Go script reads its benchmark list from benchgate/curated.txt and prints output that benchstat accepts.

terminal
# TypeScript policy engine
git clone https://github.com/glincker/theauth.git && cd theauth
pnpm install && pnpm bench

# Go hot paths (BENCH_TIME and BENCH_COUNT default to 2s and 10)
git clone https://github.com/glincker/theauth-go.git && cd theauth-go
./scripts/bench-gate.sh

Get started

Give your first agent an identity.

Install the package, create an agent with scoped permissions, and read its first audit record. The core runs on Postgres, SQLite, MySQL or D1, and the Go module needs a single go get.

  • npm install @glinr/theauth
  • go get github.com/glincker/theauth-go
Or skip hosting with theAuth Cloud