Skip to content

After a successful login if I go back in browser I get CSRF detected error #95

Open
@ristovskiv

Description

@ristovskiv

I've build an OAuth2 provider using the doorkeeper engine with devise. On my client app I'm using a custom omniauth-oauth2 -v 1.3.1 strategy. Everything works well, but after I sign in if I hit the back button on the browser I get
screenshot from 2016-07-22 14 34 04

I dug into the omniauth-oath2 code and it appears that there are two methods that I think are closely related to this problem, one that creates the session["omniauth.state"] from the url params:

def authorize_params
        options.authorize_params[:state] = SecureRandom.hex(24)
        params = options.authorize_params.merge(options_for("authorize"))
        if OmniAuth.config.test_mode
          @env ||= {}
          @env["rack.session"] ||= {}
        end
        session["omniauth.state"] = params[:state]
        params
end

and one that checks this and deletes this from the session on the callback process:

def callback_phase # rubocop:disable AbcSize, CyclomaticComplexity, MethodLength, PerceivedComplexity
        error = request.params["error_reason"] || request.params["error"]
        if error
          fail!(error, CallbackError.new(request.params["error"], request.params["error_description"] || request.params["error_reason"], request.params["error_uri"]))
        elsif !options.provider_ignores_state && (request.params["state"].to_s.empty? || request.params["state"] != session.delete("omniauth.state"))
          fail!(:csrf_detected, CallbackError.new(:csrf_detected, "CSRF detected"))
        else
          self.access_token = build_access_token
          self.access_token = access_token.refresh! if access_token.expired?
          super
        end
      rescue ::OAuth2::Error, CallbackError => e
        fail!(:invalid_credentials, e)
      rescue ::Timeout::Error, ::Errno::ETIMEDOUT => e
        fail!(:timeout, e)
      rescue ::SocketError => e
        fail!(:failed_to_connect, e)
  end

It appears that somehow the first method is not called on going back from the browser. Does someone had the same problem and is there a solution to this problem without setting the :provider_ignores_state to true. Do I need to set something on the provider, I really don't get it, plus I can't seem to find this problem anywhere on the web and I highly doubt it I'm the first one that recognizes it, but I may be the first one that can't find a reasonable solution without affecting security.

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions