Making cross-origin, browser-side API requests

Have more questions? Submit a request

25 Comments

  • Andrew Sharpe
    Comment actions Permalink

    Great writeup, thanks!


    There is one issue with using Zendesk in this way, which is the lack of CORS headers for anything other than a 200 response.


    This article implies that the lack of CORS headers is used as access control however that's built into Zendesk proper.


    If the user making the request does not have permissions to use the API endpoint (as specified by the "Allowed for" sections in the API docs), the "Access-Control-Allow-Origin" header is not included in the response. The missing CORS header prevents the user from accessing the resource in the Zendesk domain.


    The lack of CORS headers for unauthorised requests means that the client application cannot handle issues gracefully.  Zendesk is actually returning a 401, which indicates correctly the reason why the user cannot access the resource.  The same applies if the token is invalid/expired, and the app cannot make an intelligent decision without the CORS headers in the response.


    Another example is the "429 Too Many Requests" response that Zendesk can return.  Because this response doesn't have CORS headers the application does not get a chance to identify this issue and respond accordingly.


    Could Zendesk please return the CORS headers for requests that fail too?

    0
  • Charles Nadeau
    Comment actions Permalink

    Thanks very much for the feedback, Andrew. I updated the wording in the article to make this clearer. 


    I ran some quick tests and I'm able to confirm that the headers are returned on 200, 201, 204, and 404 responses. Not sure if there are any others.


    I brought this issue to the attention of the API product team.

    0
  • Manoj Tammali
    Comment actions Permalink

    Hi Charles,


    I have tried to implement the same on my Zendesk (konysolutions.zendesk.com) but the code always stops after executing "startAuthFlow" method. It redirects me to my Zendesk page rather than giving me the ticket details as said on the above html. What could the potential problem with this. I have no console errors as well on the above html page. Please do let me know.


    Thanks,


    Manoj


     

    0
  • Charles Nadeau
    Comment actions Permalink

    Hi Manoj,


    Can you share your startAuthFlow() function? It should look like this (with different values for your_redirect_url and your_unique_identifier:


    function startAuthFlow() {
    
    var endpoint = 'https://konysolutions.zendesk.com/oauth/authorizations/new';
    var url_params = '?' +
    'response_type=token' + '&' +
    'redirect_uri=your_redirect_url' + '&' +
    'client_id=your_unique_identifier' + '&' +
    'scope=' + encodeURIComponent('read write');
    window.location = endpoint + url_params;
    }

     

    0
  • Manoj Tammali
    Comment actions Permalink

    Hi Charles,


    this is the code.


     


    function startAuthFlow() {
     alert("startAuthFlow Starts");
      var endpoint = 'https://konysolutions.zendesk.com/oauth/authorizations/new';
      var url_params = '?' +
      'response_type=token' + '&' +
      'redirect_uri=https://konysolutions.zendesk.com' + '&' +
      'client_id=konysupport_cseoauth_token' + '&' +
      'scope=' + encodeURIComponent('read write');
      window.location = endpoint + url_params;
      alert("startAuthFlow ends");
    }


    One thing i am not sure is what the redirect_uri means. the value i have put here is there in my OAuth token. but why and what the redirect URI does is what i am not sure.


    Please help me on this.


    Thanks


     

    0
  • Charles Nadeau
    Comment actions Permalink

    The "redirect_uri" is one of the "Redirect URLs" defined when creating the OAuth client in the Zendesk admin interface: 



     

    0
  • Manoj Tammali
    Comment actions Permalink

    Hi Charles,


    It is the same url that i have put in code. but doesn't work.


    0
  • Charles Nadeau
    Comment actions Permalink

    Hi Manoj,


    Sorry about that. I wasn't clear about the redirect url in the article. I updated the article with the following info:


    ---


    For the Redirect URLs field, enter the URL of the web page you'll build in this tutorial. Looking ahead, the file will be named ticket_details.html.


    If you have access to a web server, enter the full url to the future file:


    https://www.example.com/my_site/ticket_details.html


    If you don't have access to a web server, you can install and run a local web server such as XAMPP on your computer. Specify a localhost url as a redirect url. Example:


    http://localhost/my_site/ticket_details.html


    For more information on XAMPP and to download it, see the Apache Friends website.


    ---


    You should then save or upload all 3 files, ticket_details.html, styles.css, and scripts.js, to the folder to be served by the web server. Make sure the url for ticket_details.html is the same as the redirect url you specified in your OAuth client.


    Charles

    0
  • Jon I.
    Comment actions Permalink

    Hi!


    I'm facing an issue with Ticket Imports.


    Cors policy states that when a resource is protected by any kind of authentication mechanism (http basic, token...) Access-Control-Allow-Credentials cannot be '*' (everywhere).


    I'm trying to implement an application which makes use of Ticket Imports and I cannot use it:



    Is there something I can do? I believe the AJAX call is being performed correctly, but the answer isn't well (the ticket gets created but I receive that error).


     My code snipet:


    var request = new XMLHttpRequest();
    request.withCredentials = true;
    var url = "https://***.zendesk.com/api/v2/imports/tickets.json";
    request.open('POST', url, true);


    request.setRequestHeader("Authorization", "Basic *****");


    request.onreadystatechange = function() {
    if (this.readyState == 4 && this.status == 200) {


    // do something


    }else{


    // do something else


    }


    };
    request.send(jsonObjStr);

    0
  • Charles Nadeau
    Comment actions Permalink

    Hi Jon,


    Zendesk only implements CORS for API requests authenticated with OAuth access tokens, not basic authentication. Example:


    request.setRequestHeader("Authorization", "Bearer " + access_token);

    See the article above for all the gory details of getting and using an OAuth access token.

    0
  • Vivace Cho
    Comment actions Permalink

    Hi

    I want to use API with localhost, so I've made OAUTH with http://127.0.0.1:8080/zoauth/ticket_details.html

    However, it keeps giving me 'invalid_token'. The only thing I changed from your demo code is putting my OAUTH token in makeRequest() manually like 'makeRequest(oauth, ticket_number)'.

    But it keeps giving me 401 unauthorized.


     

    0
  • Klara Audren
    Comment actions Permalink

    Hello Vivace,


     


    The token should be specified in the "request.setRequestHeader",please try the below


      request.setRequestHeader("Authorization", "Bearer " + token);

    0
  • Dirk Wolthuis
    Comment actions Permalink

    If I want to make a app that creates and reads tickets for unauthenticated end-users, who would I set up authentication with the Zendesk API? Or end-user do not have a Zendesk-account.

    0
  • Bryan - Community Manager
    Comment actions Permalink

    Hi Dirk,

    If you're looking to have end users create (which does not require authentication) and read their associated tickets (which does require authentication) then you should check out the /api/v2/requests.json API endpoint. It's the API that end users should use (versus the /api/v2/tickets.json endpoint, which is for agents).

    This also might be a useful article:

    Building a custom ticket form with the Zendesk API

    -1
  • Willie
    Comment actions Permalink

    I'm getting some very strange behavior when attempting to make a call to an API endpoint from within a custom ticket sidebar app. Any help would be appreciated! 

    client.get('ticket.requester.id').then( requestID => {
    var requester_tickets_url = "https://crunchyroll.zendesk.com/api/v2/users/" + requestID['ticket.requester.id'] + "/tickets/requested.json";
    console.log(requester_tickets_url);

    var r = new XMLHttpRequest();
    r.open("GET", requester_tickets_url, true);
    r.setRequestHeader('Authorization', 'Bearer ' + oauth_token)
    r.send();
    r.onreadystatechange=(e)=>{
    console.log(r.responseText)
    }

    });

    The console returns the following error:


    Access to XMLHttpRequest at 'https://crunchyroll.zendesk.com/api/v2/users/1380055993/tickets/requested.json' from origin 'https://162861.apps.zdusercontent.com' has been blocked by CORS policy: No 'Access-Control-Allow-Origin' header is present on the requested resource.

    Additionally, per the instructions, what should I put as the "redirect_url" when the app is being run from the ticket sidebar? 

     

    Thanks!

     

    ------------------ 

    Update: Issue is Resolved. Seems like using an Oauth key from the following locaiton did the trick: https://developer.zendesk.com/requests/new rather than Admin > Channels > API > Oauth

    0
  • Bryan - Community Manager
    Comment actions Permalink

    Glad you got things going Willie. Just to point out and for reference, grabbing an OAuth token from the location you mentioned is a quick way to generate one for Zendesk Support but will not work for other Zendesk products (such as Chat). This article also has some good tips for generating OAuth tokens for Zendesk Support: Using OAuth authentication with your application

    0
  • Warpist
    Comment actions Permalink

    Check out https://warpist.com as it provides managed CORS proxies to get around this issue while still being able to configure the headers precisely.

    0
  • Julien
    Comment actions Permalink

    https://develop.zendesk.com/hc/en-us/articles/360001074268/comments/360001743227

    Bryan,

    You say that the /requests.json endpoint does not require authorization for users to create but even using the https://developer.zendesk.com/requests/new API console requires authentication...

    "You must have some form of authentication"

    0
  • Bryan - Community Manager
    Comment actions Permalink

    Hi Julien,

    The Requests POST /api/v2/requests.json endpoint is unique in that in anonymous users are allowed to create requests if the Zendesk instance allows it (see the reference documentation on how to set that up).

    The test API Console mentioned is definitely not a full-featured API test tool. In fact, it only works against the Zendesk Support product. You're right in that it assumes authentication is always needed, which for the Requests API, is not necessarily true.

    If you're looking for a more full-featured API test tool, consider Postman, which does not have these limitations. While it has paid-for features (such as sharing across teams), the base/free version is enough to make these API calls. Hope this helps!

    0
  • Mikael Hedlund
    Comment actions Permalink

    Hi,

    Don't know if this is the right thread but i'm having trouble using cors from a ticket side bar application.

    The application itself doesn't call any ticket api's instead i only want to do an external api call from a "browser context" instead of the Zendesk server origin.

    So when not using cors (cors=false), the api call works fine except that the origin is from a Zendesk server that can have a lot of different ip's making it hard to allow for firewall blocking.

    Instead i want it to be "browser initiated" api call with a known browser ip managed by the firewall but i can't make it work :-(

    I receive the following error when cors is enabled (true):

    Access to XMLHttpRequest at 'https://********.lindex.com/token' from origin  https://lindex********.zendesk.com' has been blocked by CORS policy: Response to preflight request doesn't pass access control check: No 'Access-Control-Allow-Origin' header is present on the requested resource.

    0
  • Greg - Community Manager
    Comment actions Permalink

    Hi Mikael Hedlund! Have you followed the instructions for making CORS requests to external resources in this link? If so, please share the request that you're making so that we can take a look at this!

    0
  • Greg - Community Manager
    Comment actions Permalink

    I was just chatting with my colleague about this and he mentioned that this is actually a restriction on the remote server @ lindex.com preventing CORS calls. The reason that this was working with cors:false is because you’re utilizing our proxy to make these requests and thus CORS doesn’t come into play.

    The solution here would be either for the remote server to return the ‘Access-Control-Allow-Origin’ header or to utilize our proxy by passing in cors: false.

    0
  • Mikael Hedlund
    Comment actions Permalink

    Hi Greg,

    Thanks for reaching out :-)

    I belive you're right this being a restriction on the remote server...i've asked for this but it seems i didn't ask the correct question or didn't get the right answer from "remote server responsible"...

    Appreciate you answering and i'll follow up when solved.

    The main issue here is that we want allow requests from one or a few designated Zendesk servers but they are to many...don't know if there's another workaround for this if not able to activate cors on the remote server...?

    0
  • Greg - Community Manager
    Comment actions Permalink

    The reason that our whitelists are so large is that we use AWS, which means that we can not be sure what your IP will actually be. Since we may also move your account for performance reasons to a different shard or pod, if we did that, any hard-linked IP ranges would break your whitelisting and cause a potential host of problems.

    You could absolutely perform a dig on your subdomain to get the IPs that are listed for it, but this is generally not recommended since those could change at any time.

    0
  • Mikael Hedlund
    Comment actions Permalink

    Hi Greg,

    Finally got it working by disabling cors to obtain the token and then activating cors for the "data call" itself.

    Thanks for your quick response and commitment :-)

    /Mikael

    0

Please sign in to leave a comment.

Powered by Zendesk