4

I'm working on a rails api and using devise_token_auth for the authentication, when I try to update password by hitting the /auth/password with put request it responsds with error 401 i.e. unauthorized. My server logs show me this

Started PUT "/auth/password" Processing by DeviseTokenAuth::PasswordsController#update as HTML Parameters: {"password"=>"[FILTERED]", "password_confirmation"=>"[FILTERED]"} Can't verify CSRF token authenticity Completed 401 Unauthorized in

routes.rb

mount_devise_token_auth_for 'User', at: 'auth' ,:controllers => { :omniauth_callbacks => 'omniauth'  }

view.html (angularjs)

<div class="container">
    <div class="row">

    <div class="row">
       <div class="col-xs-6 col-xs-offset-3 que">
           <img src="./uploads/img/web-logo.png" class="img-responsive" alt="Logo">
       </div>
    </div>
        <div class="col-xs-12 reset-pas">
            <form  name="update_pass" ng-submit="updatePassword_controller()" role="form" class="lost_reset_password">
                <p class="error_msg" ng-show="update_pass.password_confirmation.$error.passwordVerify"> 
                    Passwords are not equal!
                </p>
            <label>New password</label>
            <input type="password" name="password"  ng-minlength="8"  ng-model="updatePasswordForm.password" required="required" class="form-control">
            <span>Minimum 8 Charachters</span>
    <br>
            <label>Re-enter new password</label>

            <input type="password" name="password_confirmation"  ng-minlength="8"  ng-model="updatePasswordForm.password_confirmation" required="required" class="form-control"  password-verify="updatePasswordForm.password" >
                <button type="submit" class="btn btn-default" id="reset-submit">Save</button>
            </form>
        </div>
    </div>
</div>

controller.js

$scope.updatePassword_controller = function() {

  $auth.updatePassword($scope.updatePasswordForm)
    .then(function(resp) {
      console.log(resp)
      $location.path('/')
    })
    .catch(function(resp) {
      console.log(resp)
    });
};

Update Note I'm facing this issue only for password update

Update

I installed gem 'angular_rails_csrf' Now it's giving only the authorization error not the csrf attack error

Mani
  • 2,391
  • 5
  • 37
  • 81
  • how are you making the request? you are missing the CSRF (authenticity_token) in your request. – zekus Mar 14 '16 at 08:43
  • @zekus dear how can i add that ? – Mani Mar 14 '16 at 08:44
  • this question was asked here http://stackoverflow.com/questions/14734243/rails-csrf-protection-angular-js-protect-from-forgery-makes-me-to-log-out-on/15761835#15761835 also check this http://solidfoundationwebdev.com/blog/posts/how-to-set-csrf-with-angularjs-and-rails. that should solve I guess. – zekus Mar 14 '16 at 08:47
  • @zekus no dear , still the same issue – Mani Mar 14 '16 at 08:52

2 Answers2

1

Use the Rails form_tag or form_for helpers. They add will add a hidden field for the XCSRF token:

<div class="container">
    <div class="row">

    <div class="row">
       <div class="col-xs-6 col-xs-offset-3 que">
           <img src="./uploads/img/web-logo.png" class="img-responsive" alt="Logo">
       </div>
    </div>
        <div class="col-xs-12 reset-pas">
            <%= form_tag "#", { "ng-submit" => "updatePassword_controller()", "role" => "form", "class" => "lost_reset_password"} do %>
                <p class="error_msg" ng-show="update_pass.password_confirmation.$error.passwordVerify"> 
                    Passwords are not equal!
                </p>
            <label>New password</label>
            <input type="password" name="password"  ng-minlength="8"  ng-model="updatePasswordForm.password" required="required" class="form-control">
            <span>Minimum 8 Charachters</span>
    <br>
            <label>Re-enter new password</label>

            <input type="password" name="password_confirmation"  ng-minlength="8"  ng-model="updatePasswordForm.password_confirmation" required="required" class="form-control"  password-verify="updatePasswordForm.password" >
                <button type="submit" class="btn btn-default" id="reset-submit">Save</button>
            </form>
        </div>
    </div>
</div>
max
  • 96,212
  • 14
  • 104
  • 165
  • my bad the template is in anuglarjs html – Mani Mar 14 '16 at 09:33
  • Do you mean that you are deploying your angular app outside of Rails with static html? In that case you need to disable the Rails CSRF protection as it relies on server side rendering. – max Mar 14 '16 at 09:35
  • If you are using token based auth you can accomplish this by removing the sessions middleware. – max Mar 14 '16 at 09:37
  • initially it was updating password , but i don't know why it stopped .plus i don't know how to remove session middleware – Mani Mar 14 '16 at 09:45
1

I simply made a condition in applicationcontroller.rb like below and it worked out . The main idea is simply to override the functionality of Devise

        if params[:controller] == "devise_token_auth/passwords" && params[:action] == "update"

              uri               = URI.parse(request.headers.env['HTTP_REFERER'])
              query_params      = CGI.parse(uri.query)
              email             = query_params['uid'].first
              user              = User.find_by_email(email)
              user.password     = params[:password]
              user.password_confirmation = params[:password_confirmation]

              if user.save
                    render json: {message: 'Password Updated successfully', status: 200}                        
              else
                    render json: {message: 'Password Could not changed , Please contact to support Team', status: 401}
              end
        end

Although it's not the proper solution but i couldn't think of anyother one . So please bear with me .In it we're fetching email from url

Jonathan Hall
  • 75,165
  • 16
  • 143
  • 189
Mani
  • 2,391
  • 5
  • 37
  • 81