Skip to content

@jwo /registrations_controller.rb
Created

Embed URL

HTTPS clone URL

Subversion checkout URL

You can clone with
or
.
Download ZIP
API JSON authentication with Devise
class Api::RegistrationsController < Api::BaseController
respond_to :json
def create
user = User.new(params[:user])
if user.save
render :json=> user.as_json(:auth_token=>user.authentication_token, :email=>user.email), :status=>201
return
else
warden.custom_failure!
render :json=> user.errors, :status=>422
end
end
end
class Api::SessionsController < Api::BaseController
prepend_before_filter :require_no_authentication, :only => [:create ]
include Devise::Controllers::InternalHelpers
before_filter :ensure_params_exist
respond_to :json
def create
build_resource
resource = User.find_for_database_authentication(:login=>params[:user_login][:login])
return invalid_login_attempt unless resource
if resource.valid_password?(params[:user_login][:password])
sign_in("user", resource)
render :json=> {:success=>true, :auth_token=>resource.authentication_token, :login=>resource.login, :email=>resource.email}
return
end
invalid_login_attempt
end
def destroy
sign_out(resource_name)
end
protected
def ensure_params_exist
return unless params[:user_login].blank?
render :json=>{:success=>false, :message=>"missing user_login parameter"}, :status=>422
end
def invalid_login_attempt
warden.custom_failure!
render :json=> {:success=>false, :message=>"Error with your login or password"}, :status=>401
end
end
@Undistraction

How do you have your routes set up for this controller?

@jwo
Owner

@1ndivisible:

My routes for api are:

namespace :api do
  devise_for :users
  resources :recipes, :only=>[:index, :show]
end  

I also go into more detail http://jessewolgamott.com/blog/2012/01/19/the-one-with-a-json-api-login-using-devise/

@Undistraction

Nice. Thanks a lot.

@dellerbie

How are you authorizing your API controllers? You don't need to add the before_filter :authorize_users! in your API::BaseController

@dellerbie

How are you authorizing your API controllers? You don't need to add the before_filter :authorize_users! in your API::BaseController?

@jwo
Owner

@dellerbie I go into more detail here: http://jessewolgamott.com/blog/2012/01/19/the-one-with-a-json-api-login-using-devise/ .. but I do this to authorize a controller that requires authorization. The above would not, since they are the sign-in and sign-up controllers.


class Api::RecipesController < Api::BaseApiController
  before_filter :authenticate_user!
  #...
end
@dellerbie

Nice, thanks for the response. Great blog post!

@Banta

Does anyone have a small sample to demonstrate this. Let me look around I'll make one when I understand.

@evanbeard

I forked this to work with latest devise: https://gist.github.com/2662058

InternalHelpers file is renamed, and made some other changes that now pass my tests

@Banta
@drblok

@jwo Have you got an example of routes.rb when using a :api namespace with a devise_for :users together with the normal devise_for :users?

Got the same problem as mentioned here: https://groups.google.com/group/plataformatec-devise/browse_thread/thread/d2f4776e5109c0b3?pli=1#

Wondering if you solved this or could point me in the right direction.

@jwo
Owner
jwo commented

@drblok -- I wouldn't have 2 devise_for... You can have separate resources :users, but I don't see the need for multiple registration paths.

@jwo
Owner
jwo commented

@drblok -- actually, sorry, that's incorrect... here's a setup for multiple devise paths. This works for me:

  devise_for :chefs, :path => '', :path_names => { :sign_in => "login", :sign_out => "logout", :sign_up => "register" }

  namespace "api/v1", :as=>:api do
    devise_for :chefs                                                                                                         
    resources :recipes, :only=>[:index, :show]
  end  

  resources :chefs, :only=>[:show,:edit, :update, :delete] do
    resource :avatar, :only=>[:show, :new, :create]
  end 
@drblok

@jwo Thanks, I'll check it out and post my findings.

@drblok

@jwo - I decided to remove the devise_for from my :api namespace and write my own as it's nothing more than rendering a JSON message if authentication fails. Thanks anyway for giving me stuff to think about to come to this conclusion ;)

@drblok
@mmcc

Thanks for the response Dennis! I ended up using a lot of your registrations controller but I did remove the user.as_json in order to be able to return the token.

render :json=> user.as_json(:auth_token=>user.authentication_token, :email=>user.email), :status=>201

to

 render :json=> { :token=>user.authentication_token, :email=>user.email }, :status=>201
@drblok

@sh1ps Errrr.. That's @jwo 's code, but glad it helps ;)

@mmcc

@drblok Errr...Well I feel like an idiot... I completely misread the flow of conversation. Thanks for offering up the help anyway!

@drblok

np!

@hackfanatic

Sorry to bring this back out from the dead, but doesn't before_filter :ensure_params_exist mean the app would also try to ensure parameters exist on destroy i.e. sign out ?

@natebird

@hackfanatic yes. The line should be before_filter :ensure_params_exist, only: :create

@johnjohndoe

I made some changes to the latest version of @Bomadeno.

@bilby91

What are the names of the helpers devise generates you? After adding namespaces i am forced to change my helpers.

namespace :api do
  namespace :v1 do
     devise_for :users
  end
end

Now i can access them like this current_api_v1_user or authenticate_api_v1_user!. Is there any way to maintain namespaces and access helper with just the name of the model?

thanks

@onetom

I agree with @bilby91 that 2 namespaces are making the current_user quite ugly. What's the best practice to avoid this?

@ricbermo

Hi there, I'm trying to make a API for a iOS app that will upload some videos to AWS s3. This is a great gist but, with the controllers are not extending from Devise::SessionsController and Devise::RegistrationsController?

@minhtriet

Try another method, taken from my Spree Application

    user = Spree::User.find_by(:email => params[:email])
    unless user.nil?
      if user.valid_password? params[:password]
        render :json => '{"api_key": "#{user.spree_api_key}"}'
      end
    end
    render :json => '{"error": "invalid email and password combination"}'

The point is that you can use valid_password? in devise for your convenient

@netwire88

Thanks minhtriet, this is useful and simpler. Do you have the RegistrationsController gist?

@DanielWright

Is there a reason not to use warden.authenticate instead of reinventing the wheel with your own finder and password-validation logic?

@coderawal

getting error
"undefined local variable or method `build_resource' for #Api::SessionsController:0x00000003f885b0"
i'm using devise 3.4.1 in rails 4.1.5, I have removed line 'include Devise::Controllers::InternalHelpers' and extended 'Api::SessionsController' < DeviseController, also I have not included the related file Api::RegistrationsController in my api does it affect ?
so what's the exact cause please clarify.

@thandang

Dear,

It's nice post.
But I have one question.
How about if I setting for Devise with maximum_attempts = 5 and lock_strategy = :failed_attempts
Does it work like normal web base.
Currently I'm using device for connect to API,

It's really helpful to get answers.
Thanks a lot.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Something went wrong with that request. Please try again.