403 Forbidden
This is an educational reference page about HTTP 403 Forbidden. The page itself is served as 200 OK so it can be indexed as HTTP documentation.
The server understood the request but refuses to fulfill it. Sending the same credentials again will not help.
Specification
Registered in the IANA HTTP Status Code Registry as Forbidden. Defined in RFC 9110, Section 15.5.4.
What it means
HTTP 403 Forbidden means the server understood the request and refuses to carry it out. If the request carried credentials, the server considers them insufficient. RFC 9110 says the client SHOULD NOT automatically repeat the request with the same credentials, but may try with different ones. A request can also be forbidden for reasons that have nothing to do with credentials, such as an IP block or a disabled feature.
When to use it
- Return 403 when the user is signed in but lacks the role, scope, or plan for the action.
- Return 403 when a token is valid but lacks the required scope. RFC 6750 maps the Bearer error insufficient_scope to 403.
- Return 403 for policy blocks such as IP allowlists, geofencing, or a CSRF check that failed.
- Return 404 instead when you do not want to reveal that the resource exists. RFC 9110 allows this.
Common causes
- The account lacks a permission, role, or OAuth scope.
- A WAF, CDN, or firewall rule blocked the request.
- File system permissions on a static file server deny read access.
- A missing or stale CSRF token on a form submission.
How to fix it
- Check which permission or scope the action needs, and grant it to the account or token.
- Read the response body. The server may say why it refused.
- For static files, check file and directory permissions and any deny rules in the web server config.
Examples
Token is valid but lacks a scope
DELETE /api/projects/88 HTTP/1.1
Host: api.example.com
Authorization: Bearer eyJhbGciOi...
HTTP/1.1 403 Forbidden
WWW-Authenticate: Bearer realm="api", error="insufficient_scope", scope="projects:delete"
Content-Type: application/problem+json
{
"type": "https://api.example.com/problems/insufficient-scope",
"title": "Missing scope",
"status": 403,
"detail": "Deleting a project requires the projects:delete scope."
}
Common mistakes
- Using 403 for missing or expired credentials. The client can fix that by authenticating, so it is 401.
- Retrying a 403 automatically with the same token. The answer will not change until permissions change.
- Revealing private resources through 403. If knowing that a resource exists is itself sensitive, return 404.
Developer notes
RFC 6750 defines the Bearer error insufficient_scope and maps it to 403, so a WWW-Authenticate header on a 403 is fine. It is optional on 403 and required on 401.
Questions
What does HTTP 403 Forbidden mean?
HTTP 403 means the server understood the request and refuses to fulfill it. The client's credentials, if any, are not enough.
What is the difference between 401 and 403?
401 means authentication is missing or invalid. 403 means the server knows who the client is, or does not care, and still refuses.
Should an API return 403 or 404 for a resource the user cannot see?
Return 404 when revealing that the resource exists would leak information. Return 403 when the user knows the resource exists and only lacks permission.
See also
Header and content rules
RFC 9110 adds no header or content rule specific to 403. The 4xx class rules also apply. See 403 in the response obligations table.