I'm using Devise on my application and would like to create a global API key that can access JSON data of anyone's account without having to log-in.
For example, say my API Key is 1234
and I have two users who have created two different restaurants.
And I open a brand new browser and haven't logged into anything and I pass into my URL .../restaurants/2.json?api_key=1234
, I should be able to access the JSON data of that restaurant without having to log-in as User 2
Whats the best way to do this?
I've followed the Railscast #352 Securing an API so I'm able to access JSON stuff by passing in the API key but I have to log-in to see anything.
I should mention that I'm also using CanCan for roles but not sure if that'll play any role (pun not intended) in this situation.
I followed the Railscast #350 and #352 which teach you how to create REST API Versioning and how to secure it with an API Key.
Here's what my controllers/api/v1/restaurants/restaurants_controller.rb looks like:
module Api
module V1
class RestaurantsController < ApplicationController
before_filter :restrict_access
respond_to :json
def index
respond_with Restaurant.all
end
def show
respond_with Restaurant.find(params[:id])
end
private
def restrict_access
api_key = ApiKey.find_by_access_token(params[:api_key])
head :unauthorized unless api_key
end
end
end
end
And my application_controller.rb
still has the before_filter :authenticate_user!
code in it.
I first followed the Railscast #350 on REST API Versioning and moved all my JSON API calls to /apps/api/v1/...
Then, following Steve Jorgensen's solution below, made sure my API module inherited from ActionController::Base
instead of ApplicationController
so that it bypassed Devise's before_filter :authenticate_user!
code within the ApplicationController
.
So, my Edit 2 code when from looking like this:
module Api
module V1
class RestaurantsController < ApplicationController
...
to
module Api
module V1
#Replace 'ApplicationController' with 'ActionController::Base'
class RestaurantsController < ActionController::Base
...
I know its been a while since this was asked, but thought I would throw in one more option that i've used in the past
class Api::ApplicationController < ApplicationController
skip_before_filter :authenticate_user!
This assumes that you have an application controller in your API directory that all of your api controllers inherit from. If not, you can just put the skip in each controller.
You can do this with your before_filter
in your Controller.
Currently, you probably have something like:
class SomeController < ApplicationController
before_filter :authenticate_user!
end
Instead of calling this, you can define a different method (ideally in ApplicationController)
class ApplicationController < ActionController::Base
before_filter :authenticate_or_token
private
def authenticate_or_token
if params[:api_key] == 1234
@current_user = User.new(:admin => true, :any => "other", :required => "fields")
return current_user
end
authenticate_user!
end
I would recommend using a more robust method of authentication such as OAuth, but this should work for a simple 1-key based authentication.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With