Slack files: XMLHttpRequest can not load response for preflight is invalid (redirect)

6

I am using angularjs@v1.3 to make a request to the api of slack . According to Slack files types I need to add the Authentication in the header. I make the request from postman and it returns the file I need.

GET /files-pri/... HTTP/1.1
Host: files.slack.com
Authorization: Bearer A_VALID_TOKEN
Cache-Control: no-cache
Postman-Token: POSTMAN_TOKEN

Now, doing this from angular returns XMLHttpRequest cannot load. Response for preflight is invalid (redirect) .

$http(
  method: 'GET',
  url: url_private_download,
  headers: {
    Authorization: 'Bearer ' + token
  }
});

I'm not sure what I'm doing wrong and why I get this error back, I've read some similar SO questions in English but it's not clear to me.

Update: In the end it seems to be a problem with OPTIONS , as I understand this , angular (or the browser, I'm not sure) just avoid OPTIONS if Content-Type=text/plain . Now, the problem is that I can only do it without the Authorization .

How do I add Authorization while avoiding preflight ?

Current request, need the Auth:

$http(
  method: 'GET',
  url: url_private_download,
  headers: {
    'Content-Type': 'text/plain',
  }
});
    
asked by learnercys 14.03.2016 в 04:37
source

3 answers

3

The reason he is giving you this problem is because the preflights have to be authorized by the server using CORS 1 2 3 , this is a security mechanism that works automatically in browsers but Postman is not a browser so the preflight is never performed and headers Origin , Access-Control-Request-Headers and Access-Control-Request-Method are not added automatically and the security mechanisms of the server are not activated.

Putting the Content-Type in text/plain will not help since putting a header of Authorization is no longer a "simple request". Any request that can potentially modify data no longer qualifies as a "simple request". This is the definition:

It must be done with a "simple method" which is a request made with one of the following verbs http:

  • GET
  • POST
  • HEAD
  • It should be done with only "simple headers" which are some of the following headers :

  • Accept
  • Accept-Language
  • Content-Language
  • Content-Type if it is one of application/x-www-form-urlencoded , multipart/form-data or text/plain
  • In your case you are using a header Authorization so the cors will be activated even if you change the Content-Type. This is a mechanism that can not be avoided as it is a crucial part of web security to avoid attacks such as the CSRF .

    Angular uses json by default for its Content-Type and I think Slack does not support it

    Sending json to slack in to http post request

    So you should do this in a config block

    $httpProvider.defaults.headers.common['Content-Type'] = 'application/x-www-form-urlencoded;charset=utf8';
    

    Or in a run block

    $http.defaults.headers.common['Content-Type'] = 'application/x-www-form-urlencoded;charset=utf8';
    

    One solution may be to send the authorization token in the query using GET. This solution I have never liked since using GET to transmit sensitive information is not a good idea. Read for more information

    Is an https query string secure

    link .

    This would also require that Slack support this type of authentication which I think is possible using a token parameter in the query link

    This would be a way of doing it

    $http(
        method: 'GET',
        url: url_private_download + '?token=' + token,
        headers: {
            // Este header no es necesario si ya lo definiste usando headers.commons
            'Content-Type': 'application/x-www-form-urlencoded;charset=utf8'
        }
    });
    

    The other solution is to obtain permission using the whole server flow but as I understand it, Slack supports cors so check that you are using link and not link to make your requests , this answer may be related:

    Post request firebase response for preflight is invalid redirect cors

        
    answered by 16.03.2016 / 15:18
    source
    1

    In a nutshell and answering your question:

      

    How do I add the Authorization avoiding the preflight?

    As you have it is fine, what happens is that as comments @devconcept browsers do something called preflights before the actual request. You must leave it as is and handle the OPTIONS requests on the backend side to let them pass in case you have a filter or other obstacle that prevents the passage of this type of requests. Also keep in mind the issue of CORS which is nothing more than the security that is implemented for AJAX requests for cross-referencing resources or beyond the scope of the current project, ie outside of the limits of the project.

    On the other hand, I recommend using $ resource instead of $ http. You can find information that compares these objects in this page .

        
    answered by 17.03.2016 в 23:14
    1

    I think devconcept explaining it very well in your answer. I was messing with CORS and Slack and I've decided to rewrite my answer with what I've found out by contributing something else.

    The request you are trying to make to download a file requires authentication, this was a change that was introduced in January 2016 and announced with this article in English

    Therefore, the file download request must include the authentication header.

    $http(
      method: 'GET',
      url: url_private_download,
      headers: {
        Authorization: 'Bearer ' + token,
        'Content-Type': 'application/x-www-form-urlencoded;charset=utf8'
      }
    }); 
    

    And, as devconcept has explained, this request activates the preflight mode by sending a first request OPTIONS that does not include the Authorization header. When Slack receives that request it responds with an 'HTTP 301' with the redirection to the login page because that request requires authentication, that is, Slack is not ready for this request.

    From the client a file download request could be made without including the Authorization header but having previously authenticated in Slack with username and password, because the authentication would be done through the cookie.

    The code would be this: (although it does not make much sense to do this from client)

    $http(
      method: 'GET',
      url: url_private_download,
      headers: {
        'Content-Type': 'application/x-www-form-urlencoded;charset=utf8'
      }
    }); 
    

    Definitely, and as you said in a comment that it was a bot, I think you are doing something on the client that you should be doing on the server and perhaps you are exposing sensitive information that could be used against you by a malicious user.

    Many times we do not repair the security issues but they are very important, to me this talk that Chema Alonso gave at DotNetSpain 2016 made me even more aware of it.

    I hope I have contributed something with my response, regards.

    Update 3/28/2016: Clarify the part of the redirection to the Slack login page, motivated by the comment of devconcept

        
    answered by 14.03.2016 в 14:55