Rails 6, Authlogic 6, Inconsistent logout behavior across browsers

598 views Asked by At

So I've been playing around with authlogic in a new Rails 6 application just to see if I'd like to start using it to simplify the authentication in some other apps. I've basically set everything up as instructed on the github repo, about as barebones as you can get. Everything seems to work fine except user logout. In Chrome, everything seems to work as expected, the user is signed out as expected. But for some reason, accessing the /logout route doesn't actually log the user out - the web console shows the user_credentials cookie never gets deleted, user stays signed in (although the flash is displayed, so the correct route is being hit).

Oddly enough, if I add the logout_on_timeout feature and manually set current_user.last_request_at to say 20 minutes ago, I'm logged out in both browsers as expected.

I'll include all relevant code below, aside from an pages#index page with links to login/out and register, the only things not your standard new Rails app boilerplate is the authlogic stuff. I have tried current_user_session.destroy, the suggested alternative of session.destroy, and manually clearing the cookies with cookies.delete.

I have a feeling this is something basic, maybe a config option having to do with how the cookies are being sent? but I've just spent several hours trying to figure out what's going on. Any ideas?

Gemfile:

gem 'scrypt', '~> 3.0'
gem 'authlogic', '~> 6.0'

UserSessionsController

class UserSessionsController < ApplicationController
  def new
    @user_session = UserSession.new
  end
  def create
    @user_session = UserSession.new(user_session_params.to_h)
    if @user_session.save
      flash[:success] = 'You have been logged in.'
      redirect_to root_path
    else
      flash.now[:danger] = 'Unable to log you in'
      render :new
    end
  end
  def destroy
    current_user_session.destroy
    # session.destroy - tried this as well
    flash[:success] = 'You have been logged out.'
    redirect_to root_path
  end

  private

    def user_session_params
      params.require(:user_session).permit(:email, :password, :remember_me)
    end
end

ApplicationController

class ApplicationController < ActionController::Base
  helper_method :current_user_session, :current_user

  private

    def current_user_session
      return @current_user_session if defined?(@current_user_session)
      @current_user_session = UserSession.find
    end

    def current_user
      return @current_user if defined?(@current_user)
      @current_user = current_user_session && current_user_session.user
    end
end

UserSession Model

class UserSession < Authlogic::Session::Base
  logout_on_timeout true
end

User Model

class User < ApplicationRecord
  acts_as_authentic do |c|
    c.crypto_provider = ::Authlogic::CryptoProviders::SCrypt
  end
  validates :email,
    format: {
      with: /@/,
      message: "should look like an email address"
    },
    length: { maximum: 100 },
    uniqueness: {
      case_sensitive: false,
      if: :will_save_change_to_email?
    }
  validates :password,
  confirmation: { if: :require_password? },
  length: {
    minimum: 8,
    if: :require_password?
  }
  validates :password_confirmation,
    length: {
      minimum: 8,
      if: :require_password?
  }
end

Basic Index View

Just to test login/out functionality

<% if current_user %>
  <p>Logged in as <strong><%= current_user.email %></strong>. <%= link_to 'Log Out', user_session_path, method: :delete %></p>
<% else %>
  <p>You are not logged in. <%= link_to 'Log In', new_user_session_path %> or <%= link_to 'Register', new_user_path %></p>
<% end %>

Finally the CreateUsers migration

class CreateUsers < ActiveRecord::Migration[6.0]
  def change
    create_table :users do |t|
      # Authlogic::ActsAsAuthentic::Email
      t.string    :email
      t.index     :email, unique: true

      # Authlogic::ActsAsAuthentic::Password
      t.string    :crypted_password
      t.string    :password_salt

      # Authlogic::ActsAsAuthentic::PersistenceToken
      t.string    :persistence_token
      t.index     :persistence_token, unique: true

      # Authlogic::ActsAsAuthentic::SingleAccessToken
      t.string    :single_access_token
      t.index     :single_access_token, unique: true

      # Authlogic::ActsAsAuthentic::PerishableToken
      t.string    :perishable_token
      t.index     :perishable_token, unique: true

      # See "Magic Columns" in Authlogic::Session::Base
      t.integer   :login_count, default: 0, null: false
      t.integer   :failed_login_count, default: 0, null: false
      t.datetime  :last_request_at
      t.datetime  :current_login_at
      t.datetime  :last_login_at
      t.string    :current_login_ip
      t.string    :last_login_ip

      # See "Magic States" in Authlogic::Session::Base
      # t.boolean   :active, default: false
      # t.boolean   :approved, default: false
      # t.boolean   :confirmed, default: false

      # Additional
      t.string :first_name
      t.string :last_name
      t.string :unconfirmed_email
      t.index :unconfirmed_email, unique: true

      t.timestamps
    end
  end
end
1

There are 1 answers

0
sthyregod On

Does your problem arise on a non-SSL environment (i.e. local test)?

In that case I would recommend trying the following fix. I had a vaguely similar problem that was fixed by this:

You'd put this in your session model. Could do something like this:

class UserSession < Authlogic::Session::Base
    secure !!Rails.application.config.force_ssl
end

(NB I think force_ssl will be removed in Rails 6.1)

Source: https://github.com/binarylogic/authlogic/issues/719#issuecomment-631509593