HTTP Status Codes Error 403: Forbidden
The server knows who you are but refuses the action: missing role, scope, IP allowlist or WAF block. Re-authenticating will not help; grant the permission or change the request.
Identify: does your log match?
HTTP/1.1 403 Forbidden
Content-Type: application/json
{"error":"forbidden","message":"Missing scope: repo:write"}- High
Missing role or OAuth scope
The token is valid but was issued without the scope (e.g. repo:write) or the user lacks the role the endpoint requires.
- Medium
WAF, CDN or IP allowlist block
Cloudflare, AWS WAF or nginx allow/deny rules reject the client IP or user agent before the app runs.
- Medium
CSRF or origin check failed
Frameworks return 403 when the CSRF token or Origin header does not match for state-changing requests.
Fix
Return 401 vs 403 deliberately
app.delete('/projects/:id', async (req, res) => { if (!req.user || req.user.role !== 'admin') return res.sendStatus(401); });
app.delete('/projects/:id', async (req, res) => { if (!req.user) return res.status(401).set('WWW-Authenticate', 'Bearer').end(); if (req.user.role !== 'admin') { return res.status(403).json({ error: 'forbidden', required: 'admin' }); } // ...delete });
Clients refresh tokens on 401 and show "no permission" on 403. Mixing them causes refresh loops.
Verify: reproduce it on purpose
$ curl -i https://httpbin.org/status/403Run it against a dev environment to trigger 403 on purpose and test your error handler.
Prevent
- Include the missing permission in the 403 body.
- Return 404 instead of 403 when existence itself is secret.
- Log the policy decision with user id and resource.
FAQ
Is 403 retryable?
No. The same request will be rejected again until permissions or the request change.
Why does S3 return 403 for a missing object?
Without s3:ListBucket, S3 hides whether a key exists and returns AccessDenied (403) instead of NoSuchKey (404).
Should I return 403 or 404 for another tenant's resource?
404 avoids leaking that the id exists. GitHub does this for private repos.
Related errors
Last verified 2026-10-21 · Source: IANA HTTP Status Code Registry (RFC 9110) · Official docs ↗ · ~49,500 searches/mo