Create a gist now

Instantly share code, notes, and snippets.

What would you like to do?
Authenticate your API with devise, token by header
#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]=your@email.com&user_login[password]=yourpassword" http://localhost:3001/api/users/sign_in --noproxy localhost
{"email":"your@email.com","success":true,"auth_token":"G3xbSrS4uqLU484eUw9h"}
#with HTTPClient
clnt = HTTPClient.new
res = clnt.post("http://localhost:3001/api/users/sign_in", {"user_login[email]" => "your@email.com", "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"})
@marcomd

This comment has been minimized.

Show comment Hide comment
@marcomd

marcomd Jul 18, 2012

With an API REST like this you can map external resource in another rails app.

#In another rails app
class Product < ActiveResource::Base
  headers['X-AUTH-TOKEN'] = 'G3xbSrS4uqLU484eUw9h'
  self.site = "http://localhost:3001/api/v1"
end
Owner

marcomd commented Jul 18, 2012

With an API REST like this you can map external resource in another rails app.

#In another rails app
class Product < ActiveResource::Base
  headers['X-AUTH-TOKEN'] = 'G3xbSrS4uqLU484eUw9h'
  self.site = "http://localhost:3001/api/v1"
end
@mateusmaso

This comment has been minimized.

Show comment Hide comment
@mateusmaso

mateusmaso Jul 23, 2012

thanks man

thanks man

@marcomd

This comment has been minimized.

Show comment Hide comment
@marcomd

marcomd Jul 24, 2012

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
Owner

marcomd commented Jul 24, 2012

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
@renanra

This comment has been minimized.

Show comment Hide comment
@renanra

renanra Jul 21, 2013

I was looking for having auth token through header. I seems prepend_before_filter did the trick.

Great gist!

renanra commented Jul 21, 2013

I was looking for having auth token through header. I seems prepend_before_filter did the trick.

Great gist!

@vfonic

This comment has been minimized.

Show comment Hide comment
@vfonic

vfonic Aug 14, 2013

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?

vfonic commented Aug 14, 2013

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?

@nihsmik

This comment has been minimized.

Show comment Hide comment
@nihsmik

nihsmik Feb 2, 2015

Thank you! I is very helpful :)

nihsmik commented Feb 2, 2015

Thank you! I is very helpful :)

@supavog

This comment has been minimized.

Show comment Hide comment
@supavog

supavog Feb 3, 2017

Any idea why I would be getting "NoMethodError (undefined method 'ensure_authentication_token!' for #User:0x007f3764a07470>):"? Where should this be defined?

supavog commented Feb 3, 2017

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