In browser's Console window, one of the following (or similar message) is displayed:
Failed to load ... No 'Access-Control-Allow-Origin' header
Cross-Origin Request Blocked: The Same Origin Policy disallows reading the remote resource ... Reason: CORS header 'Access-Control-Allow-Origin' missing
Failed to load ... Response to preflight request doesn't pass access control check: No 'Access-Control-Allow-Origin' header present on the requested resource. Origin ... is therefore not allowed access
One of the keywords usually mentioned in messages is "Access-Control-Allow-Origin".
A browser based web application (possibly an Apps framework app) is attempting to make a "cross-origin" call to get a "shared resource" from an external web service. This is known as a "CORS" request (Cross-Origin-Resource-Sharing).
There is a browser-based CORS standard that manages such cross-origin calls. When certain conditions are not met, errors such as the above will happen.
This is not necessarily a "bug." It may relate to a use-case that is intentionally not allowed by the user's web application and remote external service.
Background: When one origin (www.origin1.com) calls another origin (www.origin2.com), that is called a cross-origin request. Certain conditions have to be in place for this request to work. One is the external service being called (www.origin2.com) needs to return the HTTP header Access-Control-Allow-Origin in its response (that's a very simplified summary).
If the external service does not return this header, then the browser's adherence to the CORS specification stops the request and one of the above (or similar) errors is returned. Again, don't assume this a "bug". Understand the details and the use case before proceeding.
Ask these questions
- What is the starting point URL of the call (aka the "origin")?
This sometimes is in the error message itself.
- What is the external service's URL being called?
This is sometimes in the console's error message.
- What is being retrieved and why?
Is it a PNG file? A script, CSS, or font file? Something else? What exactly is being retrieved and what is it being used for? This can give some insights on the use-case and why this remote location's asset is important.
- Does this external resource require authentication to get? (important)
For a Zendesk example, a ticket attachment might require authentication to get if the account has "Require authentication to download" turned on. This can affect how the resource is retrieved. If a redirect is required, the Access-Control-Allow-Origin response header may not be returned and the call will fail.
Try copying the resource's URL directly into a new incognito browser tab -- does it come up there? This can be a good test of whether it can be accessed under general circumstances (but is not a guarantee that it will work in the web app's code -- just another data point to note down).
- Is OPTIONS HTTP method call seen in browser's Network tab?
When custom request headers, authentication, or other conditions exist in the cross-origin request, the browser makes an additional HTTP call. This is also called a "preflight" call. The web app's code doesn't explicitly make it; the browser in the background creates and makes it -- it's part of the CORS specification standard.
When this OPTIONS call is made, certain values need to be in this call's response for it to succeed and for the actual HTTP call for the resource to happen. If the OPTIONS call fails, then the resource is not retrieved and a CORS error should appear in the browser's console.
Note down if you see an OPTIONS call. Also note down if you see a redirect (status 302) call happening right before the OPTIONS call.
If a redirect is happening on an OPTIONS call, then the OPTIONS call will most likely fail. This means the call to get the resource will also fail and trigger a CORS error.
- What is use-case for making getting external resource?
Find out why this external resource is being retrieved in the first place. This may be important in coming up with workarounds or needed changes.
Not all CORS errors can be replicated in-house. Getting a snapshot of the failed call and what happened immediately before and after may help debug the issue and avoid the user from having to reproduce it. Headers in requests and responses can be examined, along with identifying OPTIONS calls and redirects.
Possible next steps
- Who owns the external server?
Perhaps the server can be modified to adhere to the CORS specification standard to return the Access-Control-Allow-Origin header. Keep in mind, however, that even if the server is something controlled in-house, this isn't necessarily a cure-all. There may be good reasons that a particular external service does not want to share a resource.
If the external server isn't something controlled in-house, then maybe work with that vendor or come up with another workaround, assuming the use-case is considered valid.
- Is app written using Zendesk Apps framework?
As part of the Apps framework, a back-end proxy server is available via the client.request() call. Use this proxy by setting cors:false in the client.request's settings (note: false is also the setting's default value). Because the proxy service is a back-end service, it doesn't need to adhere to the browser-based CORS specification, so the cross-origin call may possibly succeed using the proxy.
This also isn't always a cure-all. The proxy service does not support retrieving binary files or binary information from external services. There may be other app specific reasons this is not a solution, too.
- Can the resource be embedded directly into the web app?
Instead of going cross-origin to get a resource, consider including it with the web app. This avoids the cross-origin call completely (as it's now a local resource) and whatever CORS issues may go away. This isn't always a fix, however. Sometimes external resource URLs are not known ahead of time, or the resource is too large to fit as a local resource, or the resource changes too often to download it as a local static resource.
- What is browser version?
Despite the CORS specification being a standard, the error messages returned by browsers can be different. Chrome will return different console messages than Firefox. A "yellow" warning in one browser will be returned as a "red" error in another.
- Sometimes there is no "fix"
Sometimes a resource request from an external service is not meant to be shared in the context of a browser web app. The resource owner decides if it shares the resource or not. It's not up to the web app. This might be as-designed. That's why it's important to understand the use-case.