Safeguard
Security Guides•

How do you log authorization failures and access denied events?

Log every access denied decision with who, what, which rule and from where. Here are the fields, an example event and the patterns that deserve an alert.

Safeguard Security Team
4 min read

Log each access denied decision as its own event with the actor, the resource, the action attempted, the rule that said no, and the request context. Avoid logging the sensitive content of the resource. Then alert on patterns, such as one user probing many records, not on single denials.

Why denials are worth recording

Most application users never see a 403. When they do, it is usually a mistake, such as a stale bookmark. A run of denials against many different object IDs is different. It often means someone is testing whether they can read other people's data by changing an identifier in the URL.

The OWASP Logging Cheat Sheet lists authorization (access control) failures among the events to log wherever possible. OWASP Top 10 item A09 repeats the point: log login, access control and server side input validation failures with enough user context to identify suspicious accounts.

One caution from the OWASP Authorization Cheat Sheet: too much logging and too little logging can both be weaknesses. It says volume should match the application's environment and requirements. Denials are high value. Logging every successful check is rarely needed.

Fields for a denial event

FieldExampleWhy
Timestamp in UTC2026-10-19T09:14:02ZOrdering during an investigation
Event nameauthz_failEasy to query and alert on
Actor IDuser 4821Who tried
Tenant or accounttenant 77Shows cross tenant attempts
Resource type and IDinvoice 90311What they reached for
Actionread, update, deleteWhat they tried to do
Policy or ruleowner_onlyHelps tune false positives
Request IDa trace or correlation IDJoins the denial to other logs
Source IPverified client addressContext for blocking

The OWASP Logging Vocabulary gives the example name authz_fail with the user and the resource. Consistent names matter more than the exact spelling.

Steps to add it

  1. Find the single place that makes the allow or deny decision. A central middleware or policy function beats scattered checks.
  2. Emit one structured event when the answer is deny, before returning the error.
  3. Return a generic response to the client. Do not echo the rule name or the resource details back to the user.
  4. Make sure the logging call cannot throw and break the request. See logging failures must not crash your app.
  5. Check that deny by default is real. The OWASP cheat sheet says an application should be configured to deny access by default, so unexpected states end up in your denial logs rather than being allowed silently.

Alert on patterns

A single denial is noise. Useful patterns include:

  • One actor with many denials across different resource IDs in a short window.
  • A normal user hitting admin functions.
  • Denials across tenants, meaning a user touching another tenant's identifiers.
  • A sudden rise in denials after a release, which may point to a broken permission rule rather than an attack.

Start with one rule, check how often it fires, and tune it. An alert nobody acts on is not a control.

Quick check

Should denied requests return a different message to the user?

Return a generic message to the client and keep the detail in the server side log.

Do I log successful authorization checks too?

Not usually. Log successes for sensitive actions, such as admin changes and data export, where an audit trail is needed.

Safeguard's policies and gates apply the same idea to your pipeline: a failed check is recorded and acted on. Try the free scan at gold.safeguard.sh/scan.

Sources

Last reviewed: 19 October 2026.

Never miss an update

Weekly insights on software supply chain security, delivered to your inbox.

Self-healing security runs on Safeguard.

Your first fix PR is minutes away.

No sales call required, even your agent can complete the purchase over MCP.