Troubleshooting Client Access
Troubleshooting Client Access
The Diagnostic Mindset
Before reaching for DevTools, answer two questions: what exactly is failing (a whole page? one API call? just images?) and is this affecting all users or just one? A problem isolated to one user on a corporate network is almost always a firewall or proxy issue — not your code.
Open DevTools with F12, go to the Network panel, and press Escape to open the Console drawer. Most access failures produce a red Console error, a red Network entry, or both.
Step 1 — Read the Console Error
The Console almost always names the problem category before you click a single request. Here is a representative set of errors:
| Console error | Category |
|---|---|
CORS header 'Access-Control-Allow-Origin' missing | CORS — missing server header |
Mixed Content: … attempted to access 'http://…' | Mixed content — HTTP on HTTPS page |
NS_ERROR_UNKNOWN_HOST | DNS — domain cannot be resolved |
NS_ERROR_CONNECTION_REFUSED | Network — port is closed or nothing is listening |
NS_ERROR_NET_TIMEOUT | Network — firewall dropping packets silently |
SEC_ERROR_UNKNOWN_ISSUER / SSL_ERROR_BAD_CERT_DOMAIN | TLS — invalid or mismatched certificate |
ERR_TUNNEL_CONNECTION_FAILED | Proxy — CONNECT tunnel failed |
Step 2 — CORS Errors
CORS (Cross-Origin Resource Sharing) is a browser security policy. When JavaScript at https://app.example.com tries to read a response from https://api.other.com, the browser first checks whether the server sent permission headers. If not, the browser suppresses the response — even though it was received.
How a CORS request flows
Origin: https://app.example.com
Access-Control-Request-Headers: Authorization
Content-Type: application/json
⚠ Access-Control-Allow-Origin: (missing)
Access-Control-Allow-Origin: https://app.example.com
Access-Control-Allow-Headers: Content-Type, Authorization
Access-Control-Allow-Credentials: true
Investigating CORS in the Network panel
Click the blocked request → Response Headers tab. Look for:
CORS reason codes in the Console
| Reason code | Meaning |
|---|---|
CORS header 'Access-Control-Allow-Origin' missing | No header at all — add it on the server |
CORS header 'Access-Control-Allow-Origin' does not match | Wrong origin value — update the allowed-origins list |
Credential is not supported if the CORS header … is '*' | Wildcard + credentials: 'include' conflict — use a specific origin |
CORS preflight response did not succeed | OPTIONS returned non-2xx — check your OPTIONS handler |
CORS header 'Access-Control-Allow-Headers' is missing | Authorization or a custom header not listed in Allow-Headers |
Step 3 — Mixed Content
An HTTPS page that loads any sub-resource over HTTP is called mixed content. The browser blocks active mixed content (scripts, fetch requests, iframes) entirely. Passive mixed content (images, audio, video) may load but breaks the padlock icon.
Active Mixed Content (Blocked)
Scripts, XHR/Fetch calls, iframes. The browser stops the request before it leaves the machine. Status shows -- in the Network panel.
Passive Mixed Content (Warning)
Images, audio, video. May load but breaks the padlock icon and generates a Console warning. Will be blocked in future browser versions.
Finding mixed content fast
In the Network panel, press Ctrl + F to open the search bar. Type http:// — this searches request URLs and response bodies across all requests. Any hit that is an HTTP URL on an HTTPS page is a candidate for the block.
Step 4 — TLS / Certificate Errors
TLS errors prevent the browser from establishing a secure connection. They are visible on the error page Firefox shows instead of the content, and in the Security tab of Network request details.
| Error code | Meaning |
|---|---|
SEC_ERROR_EXPIRED_CERTIFICATE | Certificate is past its Not After date — renew it |
SEC_ERROR_UNKNOWN_ISSUER | Self-signed cert or private CA — browser doesn't trust the issuer |
SSL_ERROR_BAD_CERT_DOMAIN | Certificate CN/SAN doesn't match the domain in the URL |
SSL_ERROR_RX_RECORD_TOO_LONG | HTTP traffic sent to an HTTPS port — server misconfiguration |
MOZILLA_PKIX_ERROR_SELF_SIGNED_CERT | Self-signed certificate — not issued by a trusted CA |
Checking certificate details
Click the lock icon in the address bar → Connection Secure → More Information. The Security panel shows the issuer, validity period, and SANs. For sub-resource TLS errors: click the failing request in the Network panel → Security tab.
mkcert to create a local CA. Import the CA root into Firefox via Settings → Privacy & Security → Certificates → View Certificates → Import. Firefox will then trust all certs issued by that CA.
Step 5 — DNS Failures
DNS failure means the browser couldn't resolve the domain name to an IP address. Firefox shows its "Server not found" page. In DevTools, the failing request shows -- status, and the Timings tab shows only a failed DNS Lookup phase.
DNS failures are almost always environmental — DNS filtering on a corporate network, a domain that hasn't propagated yet, or an expired domain. They look similar to firewall blocks in DevTools. To tell them apart, run nslookup api.example.com in a terminal — DNS failure returns Non-existent domain; a firewall block resolves successfully but the TCP connection never completes.
Step 6 — Network / Firewall Blocks
A firewall block means DNS succeeded but the TCP connection was refused or dropped. The Timings tab distinguishes the two failure modes:
NS_ERROR_CONNECTION_REFUSEDNS_ERROR_NET_TIMEOUTStep 7 — Proxy Issues
A proxy sits between the browser and the internet. Corporate networks commonly use proxies for compliance and security. Proxy involvement is identified by response headers and specific HTTP status codes.
Identifying proxy headers
| Symptom | What the proxy is doing |
|---|---|
407 Proxy Authentication Required | Proxy requires credentials — browser didn't send them |
502 Bad Gateway from internal IP | Proxy got an invalid response from upstream |
504 Gateway Timeout from internal IP | Proxy couldn't reach upstream in time |
ERR_TUNNEL_CONNECTION_FAILED | Proxy's CONNECT tunnel for HTTPS failed |
| Certificate issuer is "Zscaler" / "BlueCoat" / "Forcepoint" | SSL inspection active — proxy is intercepting HTTPS |
Putting It All Together — Diagnostic Flow
-- → browser blocked it (CORS, mixed content, firewall, DNS)Exercises
fetch('http://example.com/test') .catch(e => console.error(e.message));Is the error a CORS error, a mixed content block, or both? Why?
Ctrl + F and type http://. Does any response on the current page contain an HTTP URL embedded in it? If so, what kind of resource is it?
Access-Control-Allow-Origin present? What is its value? Is it a wildcard (*) or a specific origin?
fetch('https://this-domain-definitely-does-not-exist-xyz.com') .catch(e => console.error('Error:', e.message));Does the Timings tab show a long DNS phase, a quick DNS then failed Connecting, or something else?
Key Takeaways
- Read the Console first — the error message names the problem category. Don't navigate the Network panel blindly when the Console has already told you what's wrong.
- CORS is enforced by the browser; the request already reached the server. Fix it by adding
Access-Control-Allow-Origin(andAccess-Control-Allow-Headersfor auth) on the server. - Wildcard + credentials conflict:
Access-Control-Allow-Origin: *cannot be used withcredentials: 'include'— use a specific origin instead. - Mixed content: any
http://resource on an HTTPS page. UseCtrl + Fin the Network panel and searchhttp://to find them quickly. - TLS errors: check the lock icon → More Information for certificate details; check Issued By to spot proxy SSL inspection.
- DNS failures show only a failed DNS Lookup phase in Timings. They are environmental — corporate filter, unpropagated domain, expired domain.
- Firewall blocks: connection refused = instant fail; firewall drop = slow timeout. The Timings tab Connecting phase distinguishes them.
- Proxy involvement is revealed by
Via,X-Cache, orX-Forwarded-Forheaders in the response, or a407status code. - Block URL (right-click any request) lets you test what happens when a resource is unavailable — ideal for resilience testing.