




3366 Members
Regulators do not just ask whether users can log in. They ask whether access is limited, justified, reviewable, and attributable. In production systems, that "prove it" expectation maps to an authorization architecture: Policy Enforcement Points (PEPs) in the application, Policy Decision Points (PDPs) that evaluate policy, and decision logs that show who tried to do what, on which resource, under which conditions, and why the answer was allow or deny.
IdP logs are necessary, but not sufficient. Login events prove authentication happened. They do not prove that a user should have been allowed to export an invoice, approve a payout, invite a tenant admin, or access another customer's data. That proof comes from application-level authorization.
A production-grade AuthZ architecture needs three core parts:
A simple production flow looks like this:
Policy Control Plane
-> OPAL syncs policy + authorization data
-> Local PDP evaluates decisions
-> PEP enforces allow/deny in the app
-> Decision logs capture evidence
For the regulatory framing, see DORA and NIST access control. For the engineering problem of repeatedly rebuilding permissions logic, see Stop Rebuilding Permissions.
A Policy Enforcement Point (PEP) is where the authorization decision is enforced. A Policy Decision Point (PDP) is where the authorization decision is made.
The PEP asks. The PDP answers. The application enforces the result.
For example, in a B2B SaaS billing product, a user attempts to export an invoice:
Can user_123 export invoice inv_789 in tenant acme?
The PEP may live inside the GET /invoices/:id/export API handler. Before returning the PDF or CSV, the handler calls the PDP. The PDP evaluates who the user is, which tenant they are in, which roles or relationships apply, the requested action and resource, and any contextual constraints such as ownership, region, account status, or environment.
The PDP returns a decision:
{
"allow": false,
"reason": "user lacks invoice.export permission for tenant acme"
}
The PEP enforces the result. The decision log records the evidence. There is also a Policy Administration Point, where policy is authored, reviewed, and promoted, but the core runtime pattern is PEP plus PDP plus logs.
A common mistake is to put every authorization decision behind a remote API call to a centralized cloud service. That may work for some low-risk workflows. It is the wrong default for critical paths.
Authorization sits on the hot path of your product: admin actions, support tools, exports, approvals, tenant isolation, data access, and service-to-service calls. If every decision depends on a remote network hop, you introduce latency, availability coupling, privacy concerns, and unclear failure modes (fail open, fail closed, retry, or cache?)
A better production pattern is hybrid:
This is the model Permit.io uses: a managed control plane with local PDPs for runtime authorization. You can read the architecture overview here: How does Permit.io work?.
The point is separation of concerns. The control plane manages policy. The PDP evaluates policy. The PEP enforces policy. Logs prove what happened.
Local PDPs solve latency, resilience, and privacy concerns. But they need current policy and data.
That is where OPAL comes in.
OPAL (Open Policy Administration Layer) distributes policy and authorization data changes to PDPs in real time. Instead of redeploying application services every time a role changes, a user joins a tenant, a relationship changes, or a resource attribute updates, OPAL syncs those changes to the authorization layer.
Modern authorization data changes constantly: tenant membership, roles, permissions, relationship tuples, resource ownership, and attributes. If those changes require app redeploys, your authorization system drifts from reality. OPAL keeps local PDPs fresh without pushing authorization logic back into every microservice.
The most important artifact in this architecture is often the least discussed: the decision log.
A decision log is not just an application line that says 403. It is structured authorization evidence: subject, action, resource, tenant or scope, relevant context, allow or deny, the reason or matched rule, timestamp, and correlation identifiers.
This is what turns authorization from code behavior into reviewable proof. During an access review, you can ask who accessed customer invoices and why they were allowed. During an incident, you can ask whether a compromised user actually had permission, or whether there was an enforcement gap. During a control assessment, you can show that high-risk actions are checked by policy, decisions are attributable, and denials are logged.
Permit provides audit log capabilities for authorization events, including filtering by log types: Audit logs: types and filtering.
Decision logs do not make an organization compliant by themselves. But without them, it is very hard to prove that access-control intent matched runtime behavior.
If you are mapping regulatory access-control expectations to architecture, look for four pillars:
That is the difference between "we think access is limited" and "we can prove how access was decided."
The mistake many teams make is treating authorization as scattered if statements: duplicated logic, inconsistent enforcement, and weak evidence. A PEP/PDP architecture separates enforcement, decisioning, policy lifecycle, realtime distribution, and audit. At Permit.io, we built around this hybrid model because authorization is too critical to be a remote-only black box and too important to remain scattered across application code.
Start with the architecture overview and the audit log documentation.

Co-Founder / CEO at Permit.io