muzicmike
muzicmike

Reputation: 113

Devise Registrations controller rejecting POST from iOS

I am trying to make an RoR backend for an iOS app. I have decided to try and secure the API using Devise (3.2.4). However, I am unable to register a user via http://localhost:3000/users as generated by devise.

I have tried using both the default devise Registrations controller as well as overriding it and creating my own.

Using restkit, my iOS app is sending this JSON:

{"user":{"email":"[email protected]", "password":"Test123", "password_confirmation":"Test123"}}

Method 1 - Standard Devise controller

Response is a 401 Unauthorized - HTTP Token: Access denied.

Started POST "/users.json" for 127.0.0.1 at 2014-08-24 18:19:34 -0400
Processing by Devise::RegistrationsController#create as JSON
  Parameters: {"user"=>{"password"=>"[FILTERED]", "password_confirmation"=>"[FILTERED]", "email"=>"[email protected]"}, "registration"=>{"user"=>{"password"=>"[FILTERED]", "password_confirmation"=>"[FILTERED]", "email"=>"[email protected]"}}}
Can't verify CSRF token authenticity
  Rendered text template (0.1ms)
Filter chain halted as :restrict_access_by_token rendered or redirected
Completed 401 Unauthorized in 5ms (Views: 2.5ms | ActiveRecord: 0.0ms)

Here, it seems that :restrict_access_by_token is being called. However, I'm not sure why as this is a post to register a new user, so I have no token to send, but am expecting one back. Also, I don't know why it doubles the parameters sent and adds a duplicate registration JSON array here.

Method 2 - Overriding Devise Registrations Controller

After the above error, I tried ignoring ':restrict_access_by_token' for the 'create' method and updated routes accordingly

routes.rb

devise_for :users, :controllers => {:registrations => "api/registrations"}

app/controllers/api/registrations_controller.rb

module API
  class RegistrationsController < Devise::RegistrationsController
  prepend_before_filter :allow_params_authentication!, :only => :create

  skip_before_filter :restrict_access_by_token, :only => :create
  respond_to :json


  def create
    user = User.new(sign_up_params)
    if user.save
      render :json=> user, :status=>201
      return
    else
      warden.custom_failure!
      render :json=> user.errors, :status=>422
    end
  end
end 
end

Response here is a 422 Unprocessable Entity and the response is :

{"email":["can't be blank"],"password":["can't be blank"]}

Server log:

Started POST "/users.json" for 127.0.0.1 at 2014-08-24 18:30:08 -0400
Processing by API::RegistrationsController#create as JSON
  Parameters: {"user"=>{"password"=>"[FILTERED]", "password_confirmation"=>"[FILTERED]", "email"=>"[email protected]"}, "registration"=>{"user"=>{"password"=>"[FILTERED]", "password_confirmation"=>"[FILTERED]", "email"=>"[email protected]"}}}
Can't verify CSRF token authenticity
   (0.1ms)  begin transaction
  User Exists (0.1ms)  SELECT 1 AS one FROM "users" WHERE "users"."email" = '[email protected]' LIMIT 1
   (0.1ms)  rollback transaction
Completed 422 Unprocessable Entity in 93ms (Views: 1.0ms | ActiveRecord: 0.3ms)

Thus it seems that somehow, Devise is getting params and then not processing them correctly. Perhaps to do with the second registration JSON array.

Any ideas on how to fix these problems? should I ditch the custom controller? How do I get rid of the registration JSON array that it seems Devise is making?

Thanks

Upvotes: 1

Views: 1030

Answers (1)

muzicmike
muzicmike

Reputation: 113

I figured out a way to get around my problem. For Method 2 above (using my custom Registrations controller) I was getting the error response:

{"email":["can't be blank"],"password":["can't be blank"]}

This was because I was sending the password_confirmation attribute as well, which is not needed for user registrations (only account updates I believe). After removing that, the JSON was parsed correctly by Devise.

For anyone having similar trouble with a Devise API, I found this gist helpful. There's a simple project here that I also used to model my JSON API to get around the deprecation of :token_authenticatable that is posted in this repo by brianweiner.

The only change I had to make was in the user.rb model. The last line of the loop generate_authentication_token should read as follows to avoid a noMethodError (based on the gist mentioned above):

      break token unless User.where(authentication_token: token).first

Upvotes: 1

Related Questions