# Debugging authorization decisions

|     |     |
| --- | --- |
|  | This documentation is for<br>an as-yet unreleased<br>version of Cerbos PDP. Choose 0.53.0 from the version picker at the top right or navigate to [https://docs.cerbos.dev](https://docs.cerbos.dev/) for the latest version. |

When a request returns an unexpected `EFFECT_ALLOW` or `EFFECT_DENY`, Cerbos provides several tools to help you understand why.

## Using `includeMeta` in requests

Add `"includeMeta": true` to your `CheckResources` request to receive metadata about how Cerbos reached each decision.

### Request with `includeMeta`

```json
{
  "requestId": "debug-example",
  "includeMeta": true,
  "principal": {
    "id": "alice",
    "roles": ["employee"],
    "attr": {
      "department": "marketing"
    }
  },
  "resources": [\
    {\
      "resource": {\
        "kind": "leave_request",\
        "id": "xx125",\
        "policyVersion": "20210210",\
        "attr": {\
          "owner": "alice"\
        }\
      },\
      "actions": ["view", "approve"]\
    }\
  ]
}
```

The response includes a `meta` block for each resource:

### Response meta block

```json
{
  "meta": {
    "actions": {
      "view": {
        "matchedPolicy": "resource.leave_request.v20210210/acme.corp",
        "matchedScope": "acme",
        "effectiveDerivedRoles": ["owner"]
      },
      "approve": {
        "matchedPolicy": "resource.leave_request.v20210210/acme.corp"
      }
    }
  }
}
```

`matchedPolicy`
The full identifier of the policy that produced the decision.

`matchedScope`
The scope that was active when the decision was made (relevant when using [scoped policies](https://docs.cerbos.dev/cerbos/prerelease/policies/scoped_policies)).

`effectiveDerivedRoles`
The [derived roles](https://docs.cerbos.dev/cerbos/prerelease/policies/derived_roles) that were activated for the principal on this resource. If a role you expected is missing, check the derived roles definition and its conditions.

## Audit logging

Enable decision logging to record every authorization decision made by the Cerbos PDP. This is useful for post-hoc analysis and for correlating decisions with application behaviour.

### Minimal audit configuration

```yaml
audit:
  enabled: true
  decisionLogsEnabled: true
  backend: file
  file:
    path: stdout
```

Every API response includes a `cerbosCallId` field. Use this identifier to locate the corresponding entry in the audit log.
See [audit configuration](https://docs.cerbos.dev/cerbos/prerelease/configuration/audit) for the full set of options including filtering, retention, and alternative backends.

## Testing CEL expressions with the REPL

The Cerbos REPL lets you evaluate CEL expressions interactively, which is useful for debugging [conditions](https://docs.cerbos.dev/cerbos/prerelease/policies/conditions) that aren’t behaving as expected.

You can load request data and test expressions against it without running a full policy evaluation cycle. See [the REPL documentation](https://docs.cerbos.dev/cerbos/prerelease/cli/cerbos#repl) for usage details.

## Common causes of unexpected DENY

If a request is denied when you expect it to be allowed, check the following:

- No matching policy

No policy exists for the `kind` and `policyVersion` combination in the request. Use `includeMeta` to confirm whether a policy was matched.

- Missing derived roles import

The [derived roles](https://docs.cerbos.dev/cerbos/prerelease/policies/derived_roles) policy is not imported into the resource policy via `importDerivedRoles`. The derived roles must be explicitly imported before they can take effect.

- Condition evaluated to false

A [condition](https://docs.cerbos.dev/cerbos/prerelease/policies/conditions) on the matching rule returned `false`. Verify that the attribute names and types in the request match what the condition expects. Use the Cerbos REPL to execute the rule with your input or write a policy test and execute it with the `--verbose` option to see how the expression is evaluated.

- Explicit DENY matched

A `DENY` rule matched for the same action. In Cerbos, deny always takes precedence over allow when both apply to the same role and action. See [how Cerbos evaluates requests](https://docs.cerbos.dev/cerbos/prerelease/policies/evaluation).

- Role mismatch

The principal’s `roles` in the request don’t match any rule in the policy. Roles are case-sensitive and must match exactly. They must be the actual role names and not the derived role names.

## Common causes of unexpected ALLOW

- Overly broad wildcards

A rule using `actions: ['']` **or `roles: ['`**`']` matches more than intended. Narrow the rule to list specific actions or roles.

- Derived role condition too permissive

A [derived role](https://docs.cerbos.dev/cerbos/prerelease/policies/derived_roles) condition is matching more principals than expected. Review the condition expression and test it in the [REPL](https://docs.cerbos.dev/cerbos/prerelease/cli/cerbos#repl).

## Validating and inspecting policies

Use `cerbos compile` to validate policies and run tests before deploying them. This catches syntax errors, missing imports, and failing test cases.
See [validating and testing](https://docs.cerbos.dev/cerbos/prerelease/policies/compile) for the full guide on policy compilation and test suites.
