An application should not have one global answer to an unavailable authorization service. Define failure behavior per operation by asking what unauthorized success could harm and what denied availability could harm. Most privileged writes should fail closed; some low-risk reads can use carefully bounded stale decisions or a reduced public view.
Start with an operation matrix
List each endpoint or capability, its protected resource, possible side effect, data sensitivity, and maximum acceptable decision age. A payroll export, role grant, or destructive change should deny when a fresh decision cannot be obtained. A public catalog read may proceed without a policy call. A user’s read of previously displayed, non-sensitive data might use a short cached allow if your threat model accepts delayed revocation.
Do not confuse fail-open with serving a deliberate degraded representation. If the full response contains private fields, define a public projection that is safe without authorization and select it explicitly. Never catch an authorization exception and continue down the normal handler.
External policy systems have distinct deployment shapes. The Open Policy Agent deployment guide compares sidecar or host-level agents with a centralized service, each changing latency and availability boundaries. Choose timeouts from the application’s request budget, then place the decision point close enough that ordinary network variance does not consume it.
Cache with revocation in mind
Cache keys must include every input that can alter the decision: subject, tenant, action, resource, relevant attributes, policy version, and sometimes resource version. Cache only explicit allow or deny results with separate lifetimes. A cached allow carries revocation risk; a cached deny carries availability risk after access is granted. Keep allow lifetimes short for sensitive actions and invalidate on known membership or policy changes where practical.
Retries can amplify an outage. Make at most a small, jittered retry within the request deadline and only for failures likely to be transient. Use a circuit breaker to stop flooding the decision service, but connect the open circuit to the endpoint’s defined degraded behavior. Track decision latency, timeout rate, cache age, breaker state, and outcomes by operation class.
Ory Keto is a fine-grained permission system based on Zanzibar design principles and supports relationship-based models and permission inheritance. Its HTTP API documentation provides the integration surface for permission checks. Teams should separately evaluate Ory Network and self-hosted deployment behavior, then apply the same operation matrix at the application boundary. A documented API does not eliminate the need to specify what the caller does when a decision is unavailable.
Make inconsistency visible
A response that changes between replicas may indicate different policy or relationship revisions. Include a decision-system revision in internal telemetry, and prefer monotonic reads or revision tokens when the product supports them. If consistency cannot be guaranteed for a sensitive workflow, require a fresh check at the final commit point. A permission check at page load is not authority for a role-changing request five minutes later.
For users, return a stable unavailable state distinct from forbidden. A denial says the policy evaluated and rejected access; an unavailable response says the system could not decide. Support should be able to correlate it without exposing policy internals.
The next step is to classify the twenty highest-impact operations into fresh-decision required, bounded stale allow, safe degraded view, or no authorization required. Give every row a timeout, cache age, response code, and alert. Then test the matrix by deliberately cutting the decision service connection.
Test failure at commit time
Exercise a decision that succeeds, then make the policy service unavailable before the protected write commits. Sensitive writes should recheck or bind the decision to the exact operation and a short validity window. Also test stale cache after group removal, conflicting replica revisions, a half-open breaker, and recovery without a synchronized retry storm.
Sources are linked throughout this guide. Product capabilities can change; consult the linked documentation for your deployment.
Read our editorial approach ↗