403 Forbidden
4xx client error
The server understood the request but refuses to allow it.
403 is a refusal. Authentication isn't the problem, or wouldn't help: the server has decided this client may not access this resource. Servers sometimes answer 404 instead, so as not to reveal that the resource exists at all.
| Class | 4xx Client Error |
|---|---|
| Retry? | No — change the request first |
| Cacheable by default | No — only with explicit Cache-Control |
| Response body | Allowed |
| Defined in | RFC 9110 §15.5.4 — 403 Forbidden |
HTTP/1.1 403 Forbidden
Content-Type: application/json
Content-Length: 21
{"error":"Forbidden"}Common causes
- The signed-in user lacks the role or permission (an admin-only endpoint).
- File permissions: the web server's user can't read the file or traverse the directory.
- Directory listing is disabled and there's no index file.
- A WAF, bot protection or IP allow-list blocked the request (Cloudflare, AWS WAF).
- A missing or invalid CSRF token on a form POST.
- Private S3 or cloud storage objects, or a signed URL that has expired.
How to fix it
- Check the user's roles against the resource's access rules.
- For static files, make files
644and directories755, readable by the web server's user. - Add an index.html, or enable directory listing only if you mean to.
- If a WAF blocked you, its logs name the rule that matched.
Useful here: 401 vs 403 · chmod 755 · chmod 644
Send a 403 from your server
res.status(403).json({ error: "Forbidden" });return Response.json({ error: "Forbidden" }, { status: 403 });return {"error": "Forbidden"}, 403http.Error(w, "Forbidden", http.StatusForbidden)
return 403;
Check what a URL returns
Print just the status line from the command line, or check a whole list of URLs at once, with their response headers, in the HTTP Status Checker.
curl -sI https://example.com/your-path | head -n 1
Frequently asked questions
403 vs 401?
401 means 'authenticate first'. 403 means 'you're authenticated, or it doesn't matter, and the answer is still no'. Retrying with the same credentials won't change a 403.
Why does nginx return 403 Forbidden?
Usually file permissions or a missing index file. nginx needs execute permission on every parent directory and read permission on the file: directories 755 and files 644 is the usual fix.
Should private resources return 403 or 404?
404 when revealing the resource exists would leak information — a private repository, another user's document. 403 when its existence is no secret.