← All Status Codes
403
Forbidden
⚠️ Client Error High Risk

📖 What Is HTTP 403?

The server understood the request but refuses to authorize it. Unlike 401, authentication will not help — the user simply does not have permission.

🛡️ Security Implications

Access control enforcement point. Ensure 403 is returned consistently for all unauthorized access attempts. Avoid information leakage in error messages.

🔍 Common Causes

Insufficient permissions, IP blocklist, WAF rule triggered, directory listing disabled, file permission issues, geographic restriction.

🔧 How to Fix

Check user permissions and roles. Review WAF rules for false positives. Verify file permissions on the server (644 for files, 755 for directories).

🖥️ How to Check

curl -I -o /dev/null -w "%{http_code}" https://example.com

HTTP 403 in depth — what you actually need to know

HTTP 403 Forbidden indicates the server understood the request and the client is authenticated, but the client does not have permission to access the resource. This is an authorisation failure (permission), distinct from 401 Unauthorized (authentication failure). Repeating the request with different credentials usually does not help — the issue is permissions for the current account, not credentials.

403 is the standard "you are not allowed here" response. Common causes: file system permission denials (web server cannot read the file), application-level access control (user role does not include this operation), WAF rules blocking the request (suspicious patterns matched), country-based restrictions (geo-blocked), or CDN/proxy access controls.

From a security perspective, 403 reveals less than 401 — both indicate "this exists, you cannot access it" but 403 specifically signals authentication is not the issue, narrowing what attackers should try. Some applications return 403 for resources that would also return 403 if the resource did not exist, to obscure existence — same information-leakage tradeoff as 401 vs 404.

Five real-world scenarios involving HTTP 403

Application-level access control

Web applications return 403 when authenticated users attempt actions outside their permission scope (e.g., regular user attempting admin operations). Standard pattern; well-implemented apps have consistent role-based access control (RBAC) or attribute-based access control (ABAC).

Bug bounty — IDOR (Insecure Direct Object Reference) testing

Hunters test whether changing IDs in requests grants access to other users' resources. URL like /api/orders/12345 — change to 12346, see if you can view another user's order. If so, broken access control finding (should return 403). One of the most common bug bounty findings.

Pentest — privilege escalation testing

Pentest authorisation testing: as low-privilege user, attempt operations requiring high-privilege (admin endpoints, user management, system configuration). Should return 403 for each. Successful operations indicate broken access control.

WAF blocking suspicious requests

Web Application Firewalls return 403 for requests matching attack patterns (SQL injection, XSS payloads, path traversal). The 403 originates from the WAF, not the application. Check WAF logs to see which rule triggered.

Geo-blocking and IP restrictions

Some content is restricted by geographic region (regulatory requirements) or IP allowlist (internal admin tools). 403 returned for requests from non-permitted regions/IPs. Easily bypassed via VPN/proxy by attackers; not a serious security control alone.

Common mistakes & edge cases

Assuming framework defaults handle authorisation

Frameworks have authentication middleware that runs by default but authorisation checks usually need explicit per-endpoint configuration. New endpoints frequently lack auth checks until someone notices. Audit comprehensively; do not trust framework defaults for authorisation.

IDOR — checking authentication but not ownership

Endpoints that verify "user is logged in" but not "user owns this resource" enable cross-user data access. Always verify the authenticated user owns or has explicit access to the requested resource (not just authenticated).

Hidden admin functionality without server-side checks

Hiding admin UI from non-admin users (in JavaScript/CSS) without server-side checks enables direct API access by anyone who finds the endpoint URL. UI hiding is convenience; server-side authorisation is the actual control.

Inconsistent authorisation between web UI and API

Common pattern: web UI checks authorisation in middleware; API endpoints (often added later) skip the same checks. Attackers go directly to API. Apply authorisation consistently across all access paths.

Returning 403 with detailed reasons that aid bypass

Error like "Access denied: requires admin role" tells attackers exactly what role to claim. Generic "Forbidden" without details forces attackers to guess. Match error verbosity to threat model.

No logging of authorisation failures

Authorisation failures may indicate attack attempts (privilege escalation, IDOR exploitation). Log them separately from authentication failures; alert on unusual rates from single users (legitimate users rarely produce many auth-failures).

Frequently Asked Questions about HTTP 403

The server understood the request and the client is authenticated, but the client does not have permission to access the requested resource. Authorisation failure (permission), distinct from 401 (authentication failure).
401 = authentication required or invalid credentials. 403 = authenticated successfully but insufficient permission for this resource. After successful login, 403 indicates "your account does not have access to this".
Several possibilities: WAF rule triggered by something in your request (often false positive), geo-blocking from your current location, account suspension or permission change, server-side configuration change. Check from different IP/network to isolate.
Insecure Direct Object Reference — vulnerability where authenticated users can access other users' resources by manipulating IDs in requests. URL /api/orders/12345 — change to 12346, see if you can view another user's order. Should return 403; if it returns 200, IDOR vulnerability.
Depends on cause. Apache: check .htaccess rules and file permissions. Nginx: check location blocks and access controls. WordPress: check security plugins and .htaccess. Application: check authorisation middleware and per-endpoint role requirements.
OWASP Top 10 #1 vulnerability. Encompasses missing authorisation checks, IDOR, privilege escalation, missing ownership verification, inconsistent enforcement between UI and API. Most common cause: developers verify authentication but forget authorisation specifically.
CDNs (Cloudflare, AWS WAF, Akamai) return 403 for requests matching attack patterns or violating configured rules. The 403 originates from the CDN, not your application. Check CDN logs to see which rule triggered. Sometimes false positives need rule tuning.
Tradeoff. Detailed errors ("requires admin role") help legitimate users understand the issue but tell attackers what to claim. Generic "Forbidden" forces attackers to guess. For high-security apps, generic; for internal tools where users need to understand permissions, more detailed.
Always verify the authenticated user has permission for the specific resource being accessed. Implementation patterns: query database with both resource ID AND user ID (returns nothing if user does not own it), use authorisation policies (Pundit in Rails, Django permissions), integration tests verifying cross-user access returns 403.
Some apps return 404 instead of 403 for unauthorised access to obscure whether the resource exists. 403 reveals "exists, you cannot access". 404 reveals nothing. Tradeoff between security through obscurity and clear error semantics; choose based on threat model.