Benchmark Results
This page documents benchmark results from testing the authorization proxy. These numbers provide a baseline for capacity planning, though actual production performance will vary based on hardware, network conditions, and workload patterns.
Test Environment
The benchmarks were run on a local development machine with all services running in Podman containers.
Component |
Details |
|---|---|
Machine |
Apple M3 Max |
Memory |
36GB RAM |
OS |
macOS Tahoe (Darwin 25.2.0) |
Container Runtime |
Podman 5.x |
Node.js |
24.x (in container) |
k6 Version |
1.5.0 |
All services ran with default container resource limits. Production deployments with dedicated resources will see different numbers.
Request Latency
The proxy adds minimal overhead to requests. Most of the time is spent in cache lookups and, when necessary, OPA policy evaluation.
Endpoint |
Requests |
Avg Latency |
p95 Latency |
Throughput |
|---|---|---|---|---|
|
6,695 |
1.2ms |
2ms |
~220 req/s |
|
2,092 |
2.2ms |
3ms |
~70 req/s |
|
2,153 |
12ms |
15ms |
~70 req/s |
Overall |
10,940 |
5.7ms |
12.4ms |
~177 req/s |
The /health endpoint shows the baseline proxy overhead. The /authorize endpoint includes JWT decoding and OPA cache lookup. Authenticated proxy requests include the full authorization flow plus time spent waiting for the downstream API.
Cache Performance
Caching dramatically reduces latency for repeated requests. The proxy uses two cache layers:
Cache Type |
Hits |
Misses |
Hit Rate |
Avg Lookup Time |
|---|---|---|---|---|
User Context (Redis) |
4,235 |
10 |
99.76% |
0.23ms |
OPA Decisions (In-Memory) |
4,238 |
7 |
99.84% |
<0.1ms |
The high hit rates reflect typical workloads where the same users make many requests. New users or cache expiration will cause misses that require backend lookups.
Cache Miss Impact
When caches miss, latency increases significantly:
Operation |
Cached |
Uncached |
|---|---|---|
User context lookup |
<1ms |
~175ms |
OPA decision |
<0.1ms |
6-11ms |
Total proxy overhead |
2-3ms |
180-200ms |
The user context lookup dominates uncached latency because it requires an API call to fetch user profile information from the CWMS Data API.
OPA Policy Evaluation
Policy evaluation happens only on cache misses. The evaluation time depends on policy complexity and the authorization decision:
Decision |
Count |
Avg Duration |
p95 Duration |
|---|---|---|---|
Allow |
3 |
6.4ms |
~10ms |
Deny |
4 |
11ms |
~25ms |
Total |
7 |
9ms |
~20ms |
Deny decisions take longer because OPA often needs to evaluate more rules before determining that access should be blocked.
Latency Breakdown
For an authenticated request, here is where time is spent:
flowchart LR
subgraph Proxy["Authorization Proxy"]
JWT[JWT Decode<br/>less than 1ms]
Redis[Redis Lookup<br/>0.23ms hit / 1.2ms miss]
OPA[OPA Check<br/>less than 0.1ms hit / 6-11ms miss]
end
subgraph Backend["Backend API"]
API[Request Processing<br/>variable]
end
Client --> JWT --> Redis --> OPA --> API --> Client
Best case (cache hits): 2-3ms total proxy overhead Worst case (cache misses): 180-200ms (dominated by user lookup API call)
Resource Utilization
During the 30-second benchmark with 10 concurrent users:
Resource |
Measurement |
|---|---|
CPU (proxy container) |
7.6 seconds total |
Heap Size |
175MB |
GC Events |
24 minor, 6 major |
Peak Connections |
13 |
The proxy maintains a steady memory footprint without significant growth over the test duration.
Throughput Under Load
The stress test ramped from 5 to 50 virtual users over 60 seconds:
VU Count |
Throughput |
p95 Latency |
Error Rate |
|---|---|---|---|
5 |
~50 req/s |
8ms |
0% |
20 |
~150 req/s |
15ms |
0% |
50 |
~180 req/s |
45ms |
0% |
Throughput scaled linearly up to about 30 VUs, then began to plateau as the proxy approached its capacity on the test hardware.
Comparison with Direct API Access
To isolate the proxy overhead, we compared requests through the proxy versus direct API calls:
Path |
Direct API |
Through Proxy |
Overhead |
|---|---|---|---|
|
8ms |
10ms |
+2ms |
|
10ms |
13ms |
+3ms |
The 2-3ms overhead includes JWT decoding, cache lookups, and header injection. For most use cases, this is negligible compared to the security benefits.
Recommendations
Based on these benchmarks:
For Production Deployment:
Deploy multiple proxy instances behind a load balancer for horizontal scaling
Use Redis Cluster or Sentinel for cache high availability
Monitor cache hit rates; rates below 90% may indicate configuration issues
For Performance Tuning:
Increase OPA decision cache TTL if policies change infrequently
Consider pre-warming the cache for known high-traffic users
Ensure Redis connection pooling is properly sized
Alerting Thresholds:
Metric |
Warning |
Critical |
|---|---|---|
p95 latency |
>100ms |
>500ms |
Cache hit rate |
<90% |
<80% |
OPA evaluation p95 |
>50ms |
>100ms |
Error rate |
>1% |
>5% |