Geonode logo
Website blocks

How to Fix a 403 Forbidden Error

Find out whether the site, its firewall or your proxy refused you, then apply the matching fix.

Updated

TL;DR

403 Forbidden means the server understood your request and refused it, and the website or its CDN firewall sends most 403s. On a VPN or proxy, turn it off and reload once; if the page opens, keep it off for that site.

What a 403 looks like on screen and in the terminal

Each layer words its refusal differently, so the text shows who sent it. Many sites replace these default server pages with their own.

WhereWhat you see
Chrome, when the 403 has an empty bodyAccess to example.com was denied / You don't have authorization to view this page. / HTTP ERROR 403
nginx default page403 Forbidden / nginx/VERSION
Apache httpd default pageForbidden / You don't have permission to access this resource.
Django site, failed CSRF checkForbidden (403) / CSRF verification failed. Request aborted.
curl with --failcurl: (22) The requested URL returned error: 403
Python urlliburllib.error.HTTPError: HTTP Error 403: Forbidden
curl, when the proxy refuses the requestCONNECT tunnel failed, response 403

Why this happens

The site, or the firewall in front of it, decided to refuse this request.

Owners set rules on IP ranges, countries, paths and methods. A common match for VPN users is the IP range itself: AWS WAF's Anonymous IP list, which owners can switch on, blocks VPNs, proxies and hosting providers.

Diagnose your 403 first

These four checks show which layer refused you before you change anything.

  • Read the 403 page; a Ray ID or CDN branding points to a firewall rule, a bare nginx or Apache page to the server.

  • Open another page on the same site; if only one path is refused, a rule or file permission covers that path.

  • Load a page, then submit its form; if only the submit gets 403, a CSRF check or a method rule refused it.

  • In a script, print the response headers; x-ratelimit-remaining: 0 or Retry-After means a rate limit, which GitHub's API can send as 403.

Solutions ranked by effectiveness

Pick the fix that matches where the 403 appears: a browser, a proxied script or your own code.

  1. Most common fix

    Keep the VPN off and contact the site

    In a browser, a site that refuses VPN traffic does it on purpose, so leave the VPN off there rather than switching servers or countries, which only goes around the owner's choice.

    1. Turn off proxy extensions and the system proxy too, since they also change your IP.

    2. If the page says CSRF verification failed, allow cookies, reload the form and resend.

    3. If the 403 stays, send the site the time and any reference ID it shows.

  2. Check next

    Fix or drop the proxy for this site

    If the proxy refuses the tunnel with 403, fix the flags or targeting values in the username. If only the proxied request gets 403, the site refuses the proxy, so stop using it there.

    URL="https://example.com/page"
    curl -sS -o /dev/null -w 'direct: %{http_code}\n' "$URL"
    curl -sS -o /dev/null -p -w 'proxy: CONNECT %{http_connect}, site %{http_code}\n' \
      -x "http://USERNAME:PASSWORD@proxy.geonode.io:9000" "$URL"
  3. For developers

    Send the login and token the site expects

    When a browser gets in but your script gets 403 even without a proxy, the site checks for something the browser sends and your script does not.

    1. Print the 403 body first; RFC 9110 lets servers state the reason there.

    2. Send the documented login or API token with every request.

    3. For a Django form, copy the csrftoken cookie into an X-CSRFToken header.

    4. Over HTTPS, also send an Origin or Referer header naming the same site.

Stop the 403 from coming back

For scripts and scheduled jobs that go back to the same site, these habits keep each run inside what the owner allows.

  1. Read robots.txt and the site's terms before the first run; robots rules alone are not permission.

  2. Ask the owner for API access or an allowlist entry, naming your tool, pages and request rate.

  3. Keep one session with its cookies for the whole job, so logins and CSRF tokens stay valid.

  4. Log the status, headers and body of every 403, so you can show the owner what was refused.

A dedicated IP for permitted collectionFor sites whose terms allow collection, at a rate the owner accepts.
Try ISP proxies

Related errors

Learn more

FAQ

It means the server understood the request and refused to fulfill it. Some servers send 404 instead to hide that a page exists, as GitHub does for private repositories.

Find out who refused you: turn off any VPN or proxy and reload, check that you are signed in, and contact the site if it still fails. Retrying the same request unchanged gets the same 403.

Owners can refuse whole countries as well as IP ranges: CloudFront geo restrictions and Cloudflare's IP/Country block both answer 403. A VPN exit abroad can be refused for its location alone.

A 401 must carry a WWW-Authenticate header naming the login scheme, so signing in can fix it. A 403 can refuse a signed-in user, and RFC 9110 says the reason may have nothing to do with credentials.

Requests sends python-requests and its version number as the User-Agent unless you set one, and a firewall rule can match that string. Set a User-Agent that names your tool, as GitHub recommends for API clients.

Yes, when the proxy's own access rules refuse the destination or your client. Squid, for example, answers those requests with 403 and its ERR_ACCESS_DENIED error page.

Make allowlisting easy for owners

Ask the owner to allow one Dedicated ISP IP that no one else uses.