Permission Checks Are the New Bottleneck: Lessons from Map Tile Delivery
Two Calls, One Request Path
Consider a typical request at a US logistics company: a dispatcher opens a route-planning dashboard in Denver. The map renders instantly — tiles stream from a CDN edge node in milliseconds. Then the app calls the authorization service to determine whether that dispatcher can view vehicle telemetry. The spinner appears. Three hundred milliseconds later, the data loads.
Nothing about that sequence is unusual. In fact, it's the norm. And the reason is simple: map tile delivery was engineered for speed decades ago, while access management largely wasn't.
What the Benchmarks Show
We ran a series of latency tests comparing common access-management lookup patterns against standard tile delivery infrastructure:
- CDN-served map tiles: 20–60 ms from major US metros
- Centralized policy engine (single region): 150–400 ms cross-country
- Authorization service with cold-start serverless function: 800 ms–2 s
- Locally evaluated policy bundle: 1–5 ms
The pattern is unmistakable. The slowest calls share three traits: they're centralized, they're chatty, and they sit on the critical path of every request.
Why Access Checks Lag Behind
Mapping APIs solved latency by embracing distribution. Tiles are static, cacheable, and identical for every user, so providers push them to hundreds of edge locations. An authorization check, by contrast, is dynamic and user-specific — which made engineers assume it couldn't be cached.
That assumption is outdated. Modern permission data is far more cache-friendly than most teams realize. A badge holder's access to Building 4 doesn't change every second. Treating every check as a live database query is a design choice, not a requirement.
Pattern One: Edge-Cached Credentials
Borrow the CDN model directly. Push signed credentials and permission summaries to edge locations — whether that's a commercial CDN, an in-region Redis cluster, or a lightweight sidecar on each node. The edge holds a short-lived, cryptographically verifiable snapshot of what a key or user can do. Verification is local; revocation propagates on a bounded TTL.
The trade-off is a revocation window measured in seconds rather than milliseconds. For most commercial access scenarios — badge entry, API scopes, dashboard permissions — that window is acceptable. For high-security contexts, pair edge caching with a synchronous revocation channel for critical revocations.
Pattern Two: Local Policy Evaluation
Instead of asking a remote service "can this principal do this action?", ship the policy itself to the point of decision. Compile your access rules into a compact bundle — WebAssembly modules and embedded policy engines have made this practical — and evaluate in-process.
The result: authorization drops from a network round trip to a function call. Teams we've worked with typically see p99 latency fall from hundreds of milliseconds to single-digit milliseconds after this migration.
Pattern Three: Design the Failure Mode First
Here's the question most teams defer until the outage: what happens when the key service is unreachable?
If your answer is "everything fails closed and the business stops," you've built a single point of failure into every request. Decide explicitly, per resource class:
- Fail closed for high-value assets — vault access, production deploys
- Fail open with degraded scope for low-risk reads, with full audit logging
- Serve the last known-good policy snapshot when the source of truth is down
Document these decisions. A fallback nobody has reviewed is a vulnerability wearing a productivity hat.
Measure What Your Users Feel
Instrument authorization as a first-class latency metric, not a footnote in your APM. Track p50 and p99 separately — averages hide the cold starts and cross-region hops that frustrate users on the East Coast calling services in Oregon.
Map tiles earned their speed through deliberate engineering: distribution, caching, and ruthless attention to the request path. Access management deserves the same discipline. Your users already notice the difference; your dashboards should show it too.