authorized uses only error in api call - devise_token_auth - ruby-on-rails

I followed the document here which is an abstract from official document and tried to make simple API calls, everything worked fine but none got through "authorized users only" error when making REST calls.
http://localhost:3000/api/v1/auth/?email=bala223344#gmail.com&password=object123&password_confirmation=object123
It is mentioned here that the headers should be sent, but i understand those are for subsquent requests

ah found the answer finally, i checked the log and it said
Can't verify CSRF token authenticity
and i went ahead and changed this ApplicationController
protect_from_forgery with: :null_session, if: Proc.new { |c| c.request.format == 'application/json' }

Related

HTTP Token: Access denied

i m getting message "**HTTP Token: Access denied**" when access via browser http://localhost:3000/api/v1/tasks.json?auth_token=szVkqLnUbdzbekV8B-n_
but when i access from terminal that's working on success curl http://localhost:3000/api/v1/moments.json -H 'Authorization: Token token="szVkqLnUbdzbekV8B-n_"'
here code
class Api::V1::TaskController < ApplicationController
before_action :autentifikasi
def index
#tasks = current_user.tasks
end
private
def autentifikasi
authenticate_or_request_with_http_token('Premium') do |token, options|
#current_user = User.find_by(authentication_token: token)
end
end
end
end
anybody help me please !! what's wrong with my code ?
There is nothing wrong with you code - the error is in your testing methodology.
The cURL example properly sends a Authorization: Token header and sends the token along as well.
Requesting http://localhost:3000/api/v1/tasks.json?auth_token=szVkqLnUbdzbekV8B-n_ in a browser would simply set params['auth_token'] as it is a query parameter. Which will of course cause the authentication to fail.
Rails and most sane frameworks do not treat HTTP headers and query parameters as equivalent. That would leave your app looking like swiss cheese.
If you want to test token based auth via a browser you should use a plugin such as Postman which allows you to setup the request headers. Better yet is to write an actual automated integration test.
A Guide to Testing Rails Applications
RSpec Rails: Request spec
Postman
It is because authenticate_or_request_with_http_token expects an Authorization: Token from in a request header.
You are setting the header in the cURL command while in browser you are passing it as a query parameter.
So there is no token in the Request Header so your method is unable to find the token when accessed via a browser.

Devise Rails API

can someone will explain to me this line of codes?
skip_before_filter :verify_authenticity_token, :if => Proc.new { |c| c.request.format == 'application/json' }
and should I use it? Why and why not. Thank you.
The verify_authenticity_token is a before_action (a method called before every controller action, known as a before_filter prior to Rails 4) that Rails uses to protect from CSRF attacks.
You can read more about how Rails does this here.
What this line of code is saying is: "if this is a JSON request then skip the CSRF check for this controller".
This is useful for JSON APIs which need to be made available to remote sites which are not on the same domain, and therefore would fail the CSRF check. This is safe, provided you make sure the API is being authenticated properly. However, if your controller is NOT going to be used by an external web application (and you are just doing AJAX stuff on your own site) then don't turn off the verify_authenticity_token check.

"WARNING: Can't verify CSRF token authenticity" error - CORS with Devise and :token_authenticatable

I have a single page app that authenticates to another domain using CORS. All the requests are JSON requests.
My app can authenticates OK and can make GET requests OK. Authentication is using token_authenticatable. I.e. all requests append '?auth_token=whatever'
So, my actual problem is that when I try to do a PUT request I get a WARNING: Can't verify CSRF token authenticity message in the rails log as well as a CanCan::AccessDenied (You are not authorized to access this page.) exception.
Simply adding skip_before_filter :verify_authenticity_token to the rails controller fixes the issue.
Therefore I can only conclude that my ajax requests are sending an invalid or empty csrf_token.
I don't really understand how that can be, since I believe I am correctly sending the X-CSRF-Token header correctly with each ajax request.
Basically, my app authenticates and Devise sends back an auth_token and a csrf_token:
render :status => 200, :json => {
:auth_token => #user.authentication_token,
:csrf_token => form_authenticity_token
}
I then store those tokens in my ajax app, and using ajaxSend in jQuery, set it up so jQuery passes those tokens with each request:
initialize: ->
#bindTo $(document), 'ajaxSend', #appendTokensToRequest
appendTokensToRequest: (event, jqXHR, options) ->
if not #authToken? then return
if #csrfToken?
jqXHR.setRequestHeader 'X-CSRF-Token', #csrfToken
if options.type is 'POST'
options.data = options.data + (if options.data.match(/\=/) then '&' else '') +
$.param auth_token:#authToken
else
options.url = options.url + (if options.url.match(/\?/) then '&' else '?') +
$.param auth_token:#authToken
I can then see in the chrome network tab, that for each GET request the auth_token param is being sent, as well as the X-CSRF-Token header.
On PUT requests however it doesn't seem to be working though.
My theory is that CORS is stuffing things up. If you make a CORS request, your browser actually makes an additional OPTIONS request first just to check that you do have permission to access this resource.
I suspect that it is the OPTIONS request which is not passing the X-CSRF-Token header, thus rails immediately invalidates the csrf_token on the rails end. Then when jQuery makes the actual PUT request the csrf_token it passes is no longer valid.
Could this be the problem?
What can I do to prove that? Chrome doesn't seem to show me the OPTIONS requests in the network tab to help me debug the issue.
It's not a major issue, because I can just turn the CSRF stuff off. But I'd like to know why it's not working.
I think you'll need to handle the OPTIONS request, which should respond with the various headers that will allow the CORS request, IIRC they are the access-control-allow-method, access-control-allow-origin and access-control-allow-headers. Because the OPTIONS request is failing, the PUT request probably isn't occurring.
I just ran into the same issue. The problem is that the _session_id cookie cannot be sent in CORS. As a result, when Rails tries to verify the token, the session[:_csrf_token] is null and Rails generates a new one before comparison.
To solve the issue, you need to enable cookie sending in CORS. Here is the Mozilla Developer Network reference. Work is needed on both the server and client side to make it work.
Client
- Refer to your client technologies document.
Server
- Set the header Access-Control-Allow-Credentials to true (string) in the response to the preflight (HTTP OPTIONS) call.
In Rails every form submission need CSRF token authenticity.
It use to submit form securely.
The CSRF token(each time) will create newly in rails when we open our Application.
If the CSRF token not passing inside our controller this WARNING will show.
We need to pass this token in all form submissions.

Rails: json response from secure action

Originally I had quite usual ajax form with json response:
def create
# created logic omitted as most likely irrelevant
render :json => {:success => true} #over simplified JSON for debug purposes
end
So far so good, works as expected. I've added security on the create action via ssl_requirement gem:
class RegistrationsController < Devise::RegistrationsController
ssl_required :create
# rest of the code omitted, 'create' action as above
end
All of a sudden I get the following in my form response (observing in HttpFox):
Error loading content (NS_ERROR_DOCUMENT_NOT_CACHED)
The create action runs as expected (enforces HTTPS, creates an object but... fails in the browser. To be specific, fails in Firefox (works on chrome). Any clues and ideas will be greatly appreciated.
Regards,
I'm not certain, but I believe your problem has to do with cross-site AJAX requests.
The fact that you are using a different protocol is making firefox believe you are making a cross-site request. Chrome, I believe, is less strict with this restriction when on local. Try visiting the site itself over https and see if the AJAX request goes through.

Rails: Accessing the username/password used for HTTP Basic Auth?

I'm building a basic API where user information can be retrieved after that user's login and password are correctly sent.
Right now I'm using something like this:
http://foo:bar#example.com/api/user.xml
So, what I need to do is access the user/password sent in the request (the foo and bar) but am not sure how to access that info in a Rails controller.
Then I'd check those variables via a quick User.find and then set those as the username and password variables for authenticate_or_request_with_http_basic.
It's possible I'm looking at this at the completely wrong way, but that's where I'm at right now. :)
The answer to your question of how to get the credentials from the request is this:
user, pass = ActionController::HttpAuthentication::Basic::user_name_and_password(request)
However authenticate_or_request_with_http_basic is all you need to do basic auth:
class BlahController < ApplicationController
before_filter :authenticate
protected
def authenticate
authenticate_or_request_with_http_basic do |username, password|
# you probably want to guard against a wrong username, and encrypt the
# password but this is the idea.
User.find_by_name(username).password == password
end
end
end
authenticate_or_request_with_http_basic will return a 401 status if credentials are not supplied, which will pop up the username/password dialog in a browser. If details are given then those are passed to the block provided. If the block returns true the request goes through. Otherwise the request processing is aborted and a 403 status is returned to the client.
You can also check out Railscast 82 (thats were the code above is from):
http://railscasts.com/episodes/82-http-basic-authentication
The rails plugin Authlogic supports this functionality (as well as much more) out of the box. You could root around in the source for it, or simply integrate it into your existing application.
Edit:
After digging around the source code for Authlogic, I found this file which uses the following piece of code to grab the username and password:
def authenticate_with_http_basic(&block)
#auth = Rack::Auth::Basic::Request.new(controller.request.env)
if #auth.provided? and #auth.basic?
block.call(*#auth.credentials)
else
false
end
end
I'd look a bit further into where it all goes, but I've got to get to bed. Hope I was of some help.

Resources