Search code examples
ruby-on-railsjsonp

How to make ajax call to my rails api using Authorization Token


I can make the following request using curl and receive a 200 OK, I'm not able to get a 200 OK with an ajax request. I've tried this below without luck

can't get this to work

$.ajax({
    beforeSend: function (xhr) { xhr.setRequestHeader ('Authorization', 'Token 6ff1fed470ec2ddaf8b3af958461990G') },
    type: "GET",
    url: "http://testurl.abc.com/api/v1/category/",
    dataType: "json"
}).done(function( msg ) {
    console.log( msg );
}).fail(function(jqXHR, textStatus, errorThrown) {
    console.log( "Request failed: " + textStatus );
    console.log( errorThrown );
});

The good request

curl http://testurl.abc.com/api/v1/category -I -H 'Authorization: Token token='6ff1fed470ec2ddaf8b3af958461990G''

HTTP/1.1 200 OK 
Cache-Control: max-age=0, private, must-revalidate
Content-length: 0
Content-Type: application/json; charset=utf-8
Date: Sat, 01 Mar 2014 05:05:45 GMT
Etag: "c676e7d052ef40b8ff298c158f8bd7af"
Server: WEBrick/1.3.1 (Ruby/2.0.0/2014-02-24)
Set-Cookie: request_method=HEAD; path=/   
X-Content-Type-Options: nosniff
X-Frame-Options: SAMEORIGIN
X-Request-Id: 7ba9b354-e3d0-4408-81df-8d5e991875e7
X-Runtime: 0.006036
X-Ua-Compatible: chrome=1
X-Xss-Protection: 1; mode=block
Connection: keep-alive

any clues appreciated.

cheers!

Update: It doesn't look like the Authorization: Token token={token} isn't being set correctly. If I edit a failed request in charles proxy to include this then it works as expected. Just a question now of figuring out why my call to setRequestHeader is being ignored.

module Api                                                                                                                                                                                                  
       module V1                                                                                                                                                                                           
         class CategoryController < ApplicationController                                                                                                                                                                                                                                                                              
        before_filter :restrict_access                                                                                                                                                                  
        def index                                                                                                                                                                                       
            @categories = Category.all                                                                                                                                                                  

            render :json => @categories, :callback => params[:callback]                                                                                                                                                                                                                                                                                                                                                                                                                                    
        end                                                                                                                                                                                             

        def restrict_access                                                                                                                                                                                                                                                                                                                                                                                         
                authenticate_or_request_with_http_token do |token, options|                                                                                                                             
                  ApiKey.exists?(access_token: token)                                                                                                                                                   
                end                                                                                                                                                                                                                                                                                                                                       
        end                                                                                                                                                                                                                                                                                                                                                                                                        
      end                                                                                                                                                                                                                                                                                                                                                                                                        
    end                                                                                                                                                                                                 
end                                                                                                                                                                                                         



class ApplicationController < ActionController::Base                                                                                                                                                        

  protect_from_forgery with: :exception                                                                                                                                                                     
  before_filter :cors_preflight_check                                                                                                                                                                       
  after_filter :cors_set_access_control_headers                                                                                                                                                             


    def cors_set_access_control_headers                                                                                                                                                                       
     headers['Access-Control-Allow-Origin'] = '*'                                                                                                                                                         
     headers['Access-Control-Allow-Methods'] = 'POST, PUT, DELETE, GET, OPTIONS'                                                                                                                          
     headers['Access-Control-Request-Method'] = '*'                                                                                                                                                       
     headers['Access-Control-Allow-Headers'] = 'Origin, X-Requested-With, Content-Type, Accept, Authorization'                                                                                            
    end                                                                                                                                                                                                       

    def cors_preflight_check                                                                                                                                                                                  
       if request.method == "OPTIONS"                                                                                                                                                                         
         headers['Access-Control-Allow-Origin'] = '*'                                                                                                                                                        
         headers['Access-Control-Allow-Methods'] = 'POST, PUT, DELETE, GET, OPTIONS'                                                                                                                         
         headers['Access-Control-Request-Method'] = '*'                                                                                                                                                      
         headers['Access-Control-Allow-Headers'] = 'Origin, X-Requested-With, Content-Type, Accept, Authorization'                                                                                           
         render :text => '', :content_type => 'text/plain'                                                                                                                                                   
       end                                                                                                                                                                                                    
     end                                                                                                                                                                                                      
  end                                                                                                                                                                                                         

Solution

  • This is some working code we use:

    (function(token) {
        var xmlhttp = new XMLHttpRequest();
        xmlhttp.open("POST","******",true);
        xmlhttp.setRequestHeader("Authorization", "Token " + token);
        xmlhttp.send();
    })(tracker);
    

    I figured your problem would be your beforeSend call, but it seems that's the recommended way to create an authentication token with $.ajax


    Rack-CORS

    You may have an issue with your CORS policy in your app

    If you're not receiving the request in production, but are locally, then it's likely a CORS issue. By using the Rack-CORS gem, you'll be able to allow different request types to endpoints you specify

    Here's the code we use:

    config.middleware.use Rack::Cors do
      allow do
        origins '*'
        resource '/data*', :headers => :any, :methods => :post
      end
    end