Code Monkey home page Code Monkey logo

Comments (15)

gonzalo-bulnes avatar gonzalo-bulnes commented on May 26, 2024

Hi @Rotimi,

The answer is yes to both questions:

  • As you correctly noticed, the CSRF protection should be disabled for an API (see the issue 37 for references). Now, once the CSRF protection is disabled, it's very important to disable this gem fallback to Devise (as explained in #49). That's the whole point of the fallback_to_devise: false option (documented in the Installation section of the README).
  • You're also correct about the second part: since there is no fallback if token authentication fails, you must restrict access to your data when current_user is missing. You could also use the require_authentication_of_entity! method (a good option IMO) written by @donbobka in this commit (take a look at #61 for context). The current release doesn't include it, and you would have to add it by yourself, but you could of course find help here if necessary.

from simple_token_authentication.

donbobka avatar donbobka commented on May 26, 2024

@Rotimi, IMO the best way of gem usage for api following:

  1. protect_from_forgery with: :null_session - It isn't a disabling of CSRF protection, it's another method of protection:
    :null_session - Provides an empty session during every request
  2. config/initializers/simple_token_authentication.rb without modification
  3. Example:
# /app/controller/api/base_controller.rb

class API::BaseController < ActionController::Base
  protect_from_forgery with: :null_session # CSRF protection for API
end

# /app/controller/api/v1/post_controller.rb

class API::V1::PostController < API::BaseController
  acts_as_token_authentication_handler_for User, only: [:new]

  def index
    # ... Accessible for unauthenticated users ...
  end

  def show
    # ... Accessible for unauthenticated users ...
  end

  def new
    # ... Only for authenticated users...
    # If current_user is missing, devise throw error with status code 401
  end
end

In this way you have a CSRF protection and devise will handle cases when current_user is missing

from simple_token_authentication.

gonzalo-bulnes avatar gonzalo-bulnes commented on May 26, 2024

Note @Rotimi: @donbobka is right, protect_from_forgery with: :null_session doesn't disable CSRF protection, that's why the skip_before_action :verify_authenticity_token, if: :json_request instruction is necessary (Rails request forgery protection documentation).

from simple_token_authentication.

gonzalo-bulnes avatar gonzalo-bulnes commented on May 26, 2024

For reference: #45

from simple_token_authentication.

donbobka avatar donbobka commented on May 26, 2024

IMO this documentation(Rails request forgery protection documentation) is obsolete. Because without verify_authenticity_token call protect_from_forgery with: :null_session do nothing.

from simple_token_authentication.

gonzalo-bulnes avatar gonzalo-bulnes commented on May 26, 2024

I may be wrong, but I think that's the point. AFAIK the CSRF protection does not make sense for API (I have previously references this post about that), that's why we disable it.

from simple_token_authentication.

donbobka avatar donbobka commented on May 26, 2024

I made PR to rails(rails/rails#15608) about this obsolete documentation. Let's look what will say rails maintainers.

My quote from this PR, why skip_before_action :verify_authenticity_token should be deleted:

:null_session was discussed in #5326. Quote from there:

null_session is another change we'd discussed, instead of resetting the session it should just assign the cookie and session objects to values which return null for everything and then send no Set-Cookie headers in the response.

Look at method handle_unverified_request

In case you call skip_before_action :verify_authenticity_token, handle_unverified_request method of NullSession class wouldn't be called. It's mean that session variable will be real session and all data populated to session will be stored for subsequent requests. That's means that api will be vulnerable for CSRF attacks.

But if you delete skip_before_action :verify_authenticity_token line. session will be NullSessionHash and all data populated to session will be lost for subsequent requests

from simple_token_authentication.

Rotimi avatar Rotimi commented on May 26, 2024

All the ideas being made @gonzalo-bulnes @donbobka are useful but it seems they highly depend on the use case. For a non-browser client it seems disabling csrf is standard but it turns out that it is not advised when a browser is consuming the json api. See: this and this

So I believe the options for a client agnostic api are:

  1. As @gonzalo-bulnes has mentioned the simplest way would be to allow csrf and the devise fallback. Then send the csrf token with every json request from the browser and mobile client. Extracting the csrf token from rails/devise on something like android/ios requires some work.

  2. Disable csrf protection and disable the devise fallback. Implement access restriction when token auth fails or current_user is missing. And finally disable cookie session storage and devise sending cookies to the clients with config.skip_session_storage. Might be code leading to vulnerabilities.

  3. Follow @donbobka steps that keep csrf and devise fallback while using protect_from_forgery with: :null_session but not using skip_before_action :verify_authenticity_token, if: :json_request. This way rails will destroy a session without a csrf token without raising an exception. See: this

I will probably go with option 3 since it preserves the simple_token_authentication and devise gems especially with their community vetting.

Thanks for the help and guidance!

PS: With this method is there a problem with devise sending session cookies on registration and login or when devise actually comes into play when current_user is missing @donbobka ?

from simple_token_authentication.

donbobka avatar donbobka commented on May 26, 2024

This way rails will destroy a session without a csrf token without raising an exception.

In this way rails works if you use protect_from_forgery with: :reset_session. As i mentioned before :null_session keeps your session and cookies untouched, at the same time for your api requests (all actions under protect_from_forgery with: :null_session) it provides an empty session (here) and empty cookies (here) and skip session update step (here).

PS: With this method is there a problem with devise sending session cookies on registration and login or when devise actually comes into play when current_user is missing @donbobka ?

Due to :null_session provides to your request empty session, devise have to authorize user with email and token every request. If pair email/token is invalid or absent, current_user would be missing, therefore authenticate_user! method of devise throws a error.

from simple_token_authentication.

gonzalo-bulnes avatar gonzalo-bulnes commented on May 26, 2024

@gertfindel

from simple_token_authentication.

BSorbus avatar BSorbus commented on May 26, 2024

Hi @gonzalo-bulnes

This configuration is correct for for Grape gem?

My application run for http and api mode.
Rails 4.2.4 Devise 3.5.6, simple_token_authentication 1.12.0, grape 0.14.0

config/initializers/simple_token_authentication.rb without modification

My User model:

class User < ActiveRecord::Base
  acts_as_token_authenticatable

  devise  :database_authenticatable, 
          :recoverable, 
          :timeoutable, 
          :registerable, 
          :confirmable, 
            :trackable, 
          :validatable,
          :lockable,
            :password_expirable,
            :secure_validatable, 
            :password_archivable, 
            :expirable,
          :authentication_keys => [:email]

  #gem 'devise_security_extension'
  #devise :password_expirable, 
  #        :secure_validatable, 
  #        :password_archivable, 
  #        :session_limitable, 
  #        :expirable

....
end

class ApplicationController < ActionController::Base
  protect_from_forgery with: :exception
  protect_from_forgery with: :null_session, :if => Proc.new { |c| c.request.format == 'application/json' }

  acts_as_token_authentication_handler_for User, fallback: :none
....
end

and routes.rb

  mount API::Base, at: "/"
end

inside app/controllers/api/v1/certificates.rb

module API  
  module V1
    class Certificates < Grape::API
      include API::V1::Defaults
      #include Devise::Controllers::Helpers

      acts_as_token_authentication_handler_for User

      resource :certificates do
        desc "Return all certificates"
          get "", root: :certificates do
            authenticate_user!
            Certificate.all
          end
        end


      end


    end
  end
end 

..and WEBrick (when run) show error:
/home/xxxxxxx/my_app/app/controllers/api/v1/certificates.rb:8:in `<class:Certificates>': undefined method `acts_as_token_authentication_handler_for' for API::V1::Certificates:Class (NoMethodError)

if uncomment
include Devise::Controllers::Helpers

...this error show to :(

What is wrong?

from simple_token_authentication.

gonzalo-bulnes avatar gonzalo-bulnes commented on May 26, 2024

Hello @BSorbus,

The Grape support is work in progress (and I need help with it from someone familiar with Grape!) The intent is described in the wiki, progress is coordinated from #138 (there are intructions there to use the experimental code), and the current bottleneck is described in #194.

I suggest you start from #194, as it contains links to the most relevant comments in #138. Please let me know in #138 if you experiment difficulties using the experimental branch, and if you are able to suggest how the Simple Token Authentication methods / callbacks should be distributed between Grape::API and Grape::Endpoint so the usage feels convenient to Grape users.

from simple_token_authentication.

BSorbus avatar BSorbus commented on May 26, 2024

Thanks for the information.
I wish ( myself too :) ) the expeditious completion of this adapter :)

from simple_token_authentication.

ratneshnavlakhe avatar ratneshnavlakhe commented on May 26, 2024

The auth_token gets created in the database when we try to create the user, how should we stop this to generate auth_token only at login POST call.

from simple_token_authentication.

gonzalo-bulnes avatar gonzalo-bulnes commented on May 26, 2024

Hello @ratneshnavlakhe,

Can you open a new issue with your question please?
You can just copy your comment in a new issue, give it a title and I'll reply to you there!

Keeping topics separate makes easier for anyone having the same question to find yours.
Thank you!

from simple_token_authentication.

Related Issues (20)

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.