6

This question may sound like a duplicate, but I have tried all steps in the other similar questions on stackoverflow but none of them worked. I am trying to connect to a Rails API using ionic.

My setup is Rails 4, Devise for authentication, simple_token_authentication gem for token based API requests and ionic for mobile app.

I'm able to login from ionic by passing a login request with a correct username and password to the devise session controller api and get a token after successful login through the devise api.

After that, when I try to access any controller's index with a get query using the access token: http://localhost:3002/api/categories?token=1098ccee839952491a4 or http://localhost:3002/api/employers?token=1098ccee839952491a4

The response is a sign_in page of devise. In the rails log, it shows

Started GET "/api/categories?token=1098ccee839952491a43" for ::1 at 2016-06-17 17:45:55 +0530
Processing by Api::CategoriesController#index as HTML
  Parameters: {"token"=>"1098ccee839952491a43"}
  User Load (0.7ms)  SELECT `users`.* FROM `users` WHERE `users`.`authentication_token` = '1098ccee839952491a43'
Completed 401 Unauthorized in 3ms (ActiveRecord: 0.7ms)


Started GET "/users/sign_in" for ::1 at 2016-06-17 17:45:55 +0530
Processing by Devise::SessionsController#new as HTML
  Rendered devise/shared/_links.html.erb (6.5ms)
  Rendered devise/sessions/new.html.erb within layouts/login (78.3ms)
Completed 200 OK in 3850ms (Views: 3847.1ms | ActiveRecord: 0.0ms)

I know for sure the token is correct as I have cross checked the token in the database. Also, I have included rack-cors gem and its configured for allowing any origin for cross domain request.

In my application.rb the cors entry looks like this

class Application < Rails::Application
    config.active_record.raise_in_transactional_callbacks = true

    config.middleware.insert_before 0, "Rack::Cors" do
      allow do
        origins '*'
        resource '*', :headers => :any, :methods => [:get, :post, :options]
      end
    end

  end

The GET request in controllers.js in ionic looks like this :-

 $http({
        method: 'GET',
        headers: 
         {
            'X-XSRF-TOKEN': window.localStorage.getItem("token") ,
         },
        url: config.apiUrl+"/categories?token="+window.localStorage.getItem("token") ,
            }).then(function successCallback(response) {
                                console.log(response);

              }, function errorCallback(response) {
                $ionicPopup.alert({
                    title: 'Alert',
                    template: response.data.message,
                });
              });   

After the request is initiated, Chrome developer console shows the following message

XMLHttpRequest cannot load http://localhost:3002/api/categories?token=1098ccee839952491a43. The request was redirected to 'http://localhost:3002/users/sign_in', which is disallowed for cross-origin requests that require preflight.

The response headers I get from the server is

General

Request URL:http://localhost:3002/api/categories?token=1098ccee839952491a43
Request Method:GET
Status Code:302 Found
Remote Address:[::1]:3002

Response Headers

view source
Access-Control-Allow-Credentials:true
Access-Control-Allow-Methods:GET, POST, OPTIONS
Access-Control-Allow-Origin:http://localhost:8100
Access-Control-Expose-Headers:
Access-Control-Max-Age:1728000
Cache-Control:no-cache
Connection:Keep-Alive
Content-Length:101
Content-Type:text/html; charset=utf-8
Date:Fri, 17 Jun 2016 12:26:13 GMT
Location:http://localhost:3002/users/sign_in
Server:WEBrick/1.3.1 (Ruby/2.2.1/2015-02-26)
Set-Cookie:_backend_session=c05LRTgzdXNVdGNFeHcwaDNtRDkxZ1RBbXFNaDFNbE1zMTV6OGhFZG1VODdON2k4ODN0ZTg3YXo5OU5hOTZkcUNmR3VTaGVRQzBOUElCNnMrODhnemVCbUhQbUs2azNHdmVnbFpoL2JiRDA5S1I4NCtsVWNhOEpqeDdoYWxXR3hHNDg5RzNRcUlpcDZ4QWswY2NmUlpYbUkvTnpaVEViNXh6ZExCZkNyTXA0allMcW1RVGg1MjRLVnpEbzlSSVk4dGRUSTNsTUZFNEFOcVJxdm1hWXNaSFEzdnlSN01DZ2FTdEJYUTdUUGxucU44cFBMbDZ6RXlhVUx2ZHArWlNCVWgyTWs2emRrSXNGbTQ3ZVVQL0NCR0E9PS0tbmFzajFXZnZnd25oUkRFRjhxSy81QT09--281b2bd6413653ca006abc80f13329d6bf3ad0f5; path=/; HttpOnly
Vary:Origin
X-Content-Type-Options:nosniff
X-Frame-Options:SAMEORIGIN
X-Request-Id:3097ec28-6d55-4c70-90c9-de221b4321e3
X-Runtime:0.021444
X-Xss-Protection:1; mode=block

Request Headers

view source
Accept:application/json, text/plain, */*
Accept-Encoding:gzip, deflate, sdch
Accept-Language:en-US,en;q=0.8
Connection:keep-alive
Host:localhost:3002
Origin:http://localhost:8100
Referer:http://localhost:8100/
User-Agent:Mozilla/5.0 (Macintosh; Intel Mac OS X 10_11_4) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/51.0.2704.84 Safari/537.36
X-XSRF-TOKEN:1098ccee839952491a43
webdev5
  • 467
  • 1
  • 8
  • 22
Donny
  • 678
  • 11
  • 34
  • can you replace set Request Headers : "Access-Control-Allow-Origin:http://localhost:8100" to "Access-Control-Allow-Origin: * " and try again – Naitik Jun 20 '16 at 09:26
  • Why do you use both X-XSRF-TOKEN header and token as query param? Clearly this is not a CORS issue, there is something wrong in your controller with authentication. If it was CORS problem you wouldn't see the GET request at all. Can you share your code in `Api::CategoriesController` – Chris Jun 21 '16 at 11:29
  • See the answer at http://stackoverflow.com/questions/34949492/cors-request-with-preflight-and-redirect-disallowed-workarounds/39728229#39728229 for details of how to work around this. Also as noted there, this restriction on redirects is no longer in the spec but browsers need to update their implementations to match the spec change. – sideshowbarker Jan 18 '17 at 10:39

2 Answers2

0

try this

app.config(function($sceDelegateProvider) {
 $sceDelegateProvider.resourceUrlWhitelist([
    // Allow same origin resource loads.
    'self',
    // Allow loading from our assets domain.  Notice the difference between * and **.
    'http://localhost:3002/**'
  ]);

});

Browser automatically bloc resource from a stranger url you need to allow domain.

HaikelO
  • 106
  • 5
0

I think the issue related with Access-Control-Allow-Credentials:true header, try this:

$http({
        method: 'GET',
        withCredentials: true,
        headers: 
         {
            'X-XSRF-TOKEN': window.localStorage.getItem("token") ,
         },
        url: config.apiUrl+"/categories?token="+window.localStorage.getItem("token") ,
            }).then(function successCallback(response) {
                                console.log(response);

              }, function errorCallback(response) {
                $ionicPopup.alert({
                    title: 'Alert',
                    template: response.data.message,
                });
              });   

it will send cookies to api server as well

Mikalai
  • 1,515
  • 8
  • 21
  • Excellent catch ! Reading the response headers more closely was the key to understand work around to this issue. – Donny Jun 25 '16 at 15:18