Created
July 17, 2012 12:18
-
-
Save marcomd/3129118 to your computer and use it in GitHub Desktop.
Authenticate your API with devise, token by header
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#Session controller provides a token | |
#/controllers/api/sessions_controller.rb | |
class Api::SessionsController < Devise::SessionsController | |
before_filter :authenticate_user!, :except => [:create] | |
before_filter :ensure_params_exist, :except => [:destroy] | |
respond_to :json | |
def create | |
resource = User.find_for_database_authentication(:email => params[:user_login][:email]) | |
return invalid_login_attempt unless resource | |
if resource.valid_password?(params[:user_login][:password]) | |
sign_in(:user, resource) | |
resource.ensure_authentication_token! | |
render :json=> {:auth_token=>resource.authentication_token, :email=>resource.email}, :status => :ok | |
return | |
end | |
invalid_login_attempt | |
end | |
def destroy | |
resource = User.find_by_authentication_token(params[:auth_token]||request.headers["X-AUTH-TOKEN"]) | |
resource.authentication_token = nil | |
resource.save | |
sign_out(resource_name) | |
render :json => {}.to_json, :status => :ok | |
end | |
protected | |
def ensure_params_exist | |
return unless params[:user_login].blank? | |
render :json=>{:message=>"missing user_login parameter"}, :status=>422 | |
end | |
def invalid_login_attempt | |
render :json=> {:message=>"Error with your login or password"}, :status=>401 | |
end | |
end | |
#Base controller which inherited by every api controller | |
#/controllers/api/base_controller.rb | |
class Api::BaseController < InheritedResources::Base | |
before_filter :authenticate_user! | |
prepend_before_filter :get_auth_token | |
respond_to :xml, :json | |
private | |
def get_auth_token | |
if auth_token = params[:auth_token].blank? && request.headers["X-AUTH-TOKEN"] | |
params[:auth_token] = auth_token | |
end | |
end | |
end | |
#Your resources controllers | |
#/controllers/api/v1/products_controller.rb | |
module Api | |
module V1 | |
class ProductsController < Api::BaseController | |
end | |
end | |
end | |
#Routes | |
namespace :api, :defaults => {:format => 'json'} do | |
devise_for :users | |
namespace :v1 do | |
resources :products | |
end | |
end | |
#*** How to get a token: well, you have to provide email and password *** | |
#with curl | |
curl -d "user_login[email][email protected]&user_login[password]=yourpassword" http://localhost:3001/api/users/sign_in --noproxy localhost | |
{"email":"[email protected]","success":true,"auth_token":"G3xbSrS4uqLU484eUw9h"} | |
#with HTTPClient | |
clnt = HTTPClient.new | |
res = clnt.post("http://localhost:3001/api/users/sign_in", {"user_login[email]" => "[email protected]", "user_login[password]" => "yourpassword"}) | |
auth_token = JSON(res.body)["auth_token"] | |
=> "G3xbSrS4uqLU484eUw9h" | |
#*** How to get data using the token *** | |
#with curl | |
curl -H "X-AUTH-TOKEN: G3xbSrS4uqLU484eUw9h" http://localhost:3001/api/v1/products/1 --noproxy localhost --get | |
#with HTTPClient gem | |
clnt = HTTPClient.new | |
clnt.get("http://localhost:3001/api/v1/products/1", nil, {"X-AUTH-TOKEN" => "G3xbSrS4uqLU484eUw9h"}).content | |
#*** At the end, remove the access token *** | |
#with curl | |
curl -X DELETE -H "X-AUTH-TOKEN: G3xbSrS4uqLU484eUw9h" http://localhost:3001/api/users/sign_out | |
#with HTTPClient gem | |
clnt.delete("http://localhost:3001/api/users/sign_out", {"X-AUTH-TOKEN" => "G3xbSrS4uqLU484eUw9h"}) | |
Np :)
I just added routes.
If you have operations extra rest, for example close:
namespace :api, :defaults => {:format => 'json'} do
devise_for :users
namespace :v1 do
resources :products do
member do
get 'close'
end
end
end
end
then, in your client application, you can use it with active resource model (first comment) in this manner
Product.find(1).get :close
I was looking for having auth token through header. I seems prepend_before_filter did the trick.
Great gist!
Does this approach leave open the possibility of CSRF?
If you use before_filter :authenticate_user!, it will check to see if user is logged in by any possible mean (not only auth_token), and if CSRF token is not checked, another website can get your data, right?
Thank you! I is very helpful :)
Any idea why I would be getting "NoMethodError (undefined method 'ensure_authentication_token!' for #User:0x007f3764a07470>):"? Where should this be defined?
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
thanks man