Reputation: 661
Hi thanks for viewing my question. I'm building out a Rails API which works with a React front end on a different server. I'm using the Devise Token Auth gem, and am able to successfully log in, log out, and make get requests for multiple resources without any problems. To handle the changing tokens I am updating the headers on each request.
The problem I am running into is when I try to make a PUT request to update a resource, in which case I get a 401. Full error message:
Started PUT "/api/stores/3/orders/1" for 127.0.0.1 at 2017-07-12 16:00:05 -0400
Processing by Api::OrdersController#update as HTML
Parameters: {"order"=>{"id"=>1, "provider_notes"=>"tailor notes"}, "headers"=>{"client"=>"YVa0NIlxAdm6BLQXk0xeJw", "access-token"=>"bNc9BB0TgICIJzGfM4H_6A", "uid"=>"joe@joestailor.com"}, "store_id"=>"3", "id"=>"1"}
Can't verify CSRF token authenticity.
Filter chain halted as :authenticate_user! rendered or redirected
Completed 401 Unauthorized in 1ms (Views: 0.1ms | ActiveRecord: 0.0ms)
After checking, the access-token printed in the error message is in fact the token i got from the last request, so it should be good. Here's the controller I am working with. I'm not able to get passed the authenticate_user! before action.
class Api::OrdersController < ApplicationController
before_action :authenticate_user!
before_action :set_order, only: [:show, :update]
def index
render :json => current_user.store.open_orders.as_json(include: [:customer], methods: [:alterations_count])
end
def show
render :json => @order.as_json(include: [:customer, :items => {include: :item_type}])
end
def update
if @order.update(order_params)
render :json => @order
.as_json(include: [:customer, :items => {include: :item_type}])
else
byebug
end
end
private
def set_order
@order = Order.find(params[:id])
end
def order_params
if current_user.tailor?
params.require(order).permit(:requester_notes, :arrived, :fulfilled)
end
end
end
Any reason why a put request might work differently than the get requests I've been using (for this same controller)? Any advice to get around this with the Devise Auth Token would be awesome. Thanks.
Upvotes: 0
Views: 1358
Reputation: 798
If you want to use :authenticate_user!
or similar, then make sure to pass in all the necessary parameters:
It looks like you were missing expiry
and token-type
.
This will result in the user being authenticated and the current_user
being set as expected, assuming the token and credentials are valid.
Note: these headers my need to be exposed in your CORS configuration:
Rails.application.config.middleware.insert_before 0, Rack::Cors do
allow do
origins '*'
resource "*",
expose: %w[access-token expiry token-type uid client],
headers: :any,
methods: :any
end
end
Another Note: If you mounted your devise endpoint inside the api, then you will need to call a different :authenticate_user!
method.
example:
namespace :api, defaults: { format: 'json' } do
namespace :v1 do
mount_devise_token_auth_for 'User', at: 'auth'
# API routing and resources
end
end
Then you would need to call :authenticate_api_v1_user!
instead.
example:
class Api::V1::ApiController < ApplicationController
before_action :authenticate_api_v1_user!
end
Upvotes: 0
Reputation: 2513
are you using :authenticate_user! from devise?
if yes, it can't work for api you need create your own helper method
you can put it in your api application_controller/model_controller
or cretae a module and include it wherever you need
then change the before action into authenticate_with_token!
def current_user_api
@current_user ||= User.find_by(auth_token: request.headers['Authorization'])
end
def user_signed_in_api?
current_user_api.present?
end
def authenticate_with_token!
render json: { errors: "Not authenticated" },
status: :unathorized unless user_signed_in_api?
end
this book chapter 5 will help you http://apionrails.icalialabs.com/book/chapter_five
and for Can't verify CSRF token authenticity.
you can put this in your application controller
protect_from_forgery with: :null_session
skip_before_action :verify_authenticity_token, if: :json_request?
protected
def json_request?
request.format.json?
end
Upvotes: 1