XUtils

Clearance

Small and simple email & password based authentication for Rails.


Clearance

Build Status Code Climate Documentation Quality

Rails authentication with email & password.

Clearance is intended to be small, simple, and well-tested. It has opinionated defaults but is intended to be easy to override.

Please use GitHub Issues to report bugs. If you have a question about the library, please use the clearance tag on Stack Overflow. This tag is monitored by contributors.

Getting Started

Clearance is a Rails engine tested against Rails >= 6.1 and Ruby >= 3.0.0.

You can add it to your Gemfile with:

gem "clearance"

Run the bundle command to install it.

After you install Clearance, you need to run the generator:

rails generate clearance:install

The Clearance install generator:

  • Inserts Clearance::User into your User model
  • Inserts Clearance::Controller into your ApplicationController
  • Creates an initializer file to allow further configuration.
  • Creates a migration file that either create a users table or adds any necessary columns to the existing table.

Configure

Override any of these defaults in config/initializers/clearance.rb:

Clearance.configure do |config|
  config.allow_sign_up = true
  config.cookie_domain = ".example.com"
  config.cookie_expiration = lambda { |cookies| 1.year.from_now.utc }
  config.cookie_name = "remember_token"
  config.cookie_path = "/"
  config.routes = true
  config.httponly = true
  config.mailer_sender = "reply@example.com"
  config.password_strategy = Clearance::PasswordStrategies::BCrypt
  config.redirect_url = "/"
  config.url_after_destroy = nil
  config.url_after_denied_access_when_signed_out = nil
  config.rotate_csrf_on_sign_in = true
  config.same_site = nil
  config.secure_cookie = Rails.configuration.force_ssl
  config.signed_cookie = false
  config.sign_in_guards = []
  config.user_model = "User"
  config.parent_controller = "ApplicationController"
  config.sign_in_on_password_reset = false
end

Use

Access Control

Use the require_login filter to control access to controller actions.

class ArticlesController < ApplicationController
  before_action :require_login

  def index
    current_user.articles
  end
end

Clearance also provides routing constraints that can be used to control access at the routing layer:

Blog::Application.routes.draw do
  constraints Clearance::Constraints::SignedIn.new { |user| user.admin? } do
    root to: "admin/dashboards#show", as: :admin_root
  end

  constraints Clearance::Constraints::SignedIn.new do
    root to: "dashboards#show", as: :signed_in_root
  end

  constraints Clearance::Constraints::SignedOut.new do
    root to: "marketing#index"
  end
end

Helper Methods

Use current_user, signed_in?, and signed_out? in controllers, views, and helpers. For example:

<% if signed_in? %>
  <%= current_user.email %>
  <%= button_to "Sign out", sign_out_path, method: :delete %>
<% else %>
  <%= link_to "Sign in", sign_in_path %>
<% end %>

Password Resets

When a user resets their password, Clearance delivers them an email. You should change the mailer_sender default, used in the email’s “from” header:

Clearance.configure do |config|
  config.mailer_sender = "reply@example.com"
end

Integrating with Rack Applications

Clearance adds its session to the Rack environment hash so middleware and other Rack applications can interact with it:

class Bubblegum::Middleware
  def initialize(app)
    @app = app
  end

  def call(env)
    if env[:clearance].signed_in?
      env[:clearance].current_user.bubble_gum
    end

    @app.call(env)
  end
end

Overriding Clearance

Routes

See config/routes.rb for the default set of routes.

As of Clearance 1.5 it is recommended that you disable Clearance routes and take full control over routing and URL design. This ensures that your app’s URL design won’t be affected if the gem’s routes and URL design are changed.

To disable the routes, change the routes configuration option to false:

Clearance.configure do |config|
  config.routes = false
end

You can optionally run rails generate clearance:routes to dump a copy of the default routes into your application for modification.

Controllers

See app/controllers/clearance for the default behavior. Many protected methods were extracted in these controllers in an attempt to make overrides and hooks simpler.

To override a Clearance controller, subclass it and update the routes to point to your new controller (see the “Routes” section).

class PasswordsController < Clearance::PasswordsController
class SessionsController < Clearance::SessionsController
class UsersController < Clearance::UsersController

Redirects

The post-action redirects in Clearance are simple methods which can be overridden one by one, or configured globally.

These “success” methods are called for signed in users, and redirect to Clearance.configuration.redirect_url (which is / by default):

  • passwords#url_after_update
  • sessions#url_after_create
  • sessions#url_for_signed_in_users
  • users#url_after_create
  • application#url_after_denied_access_when_signed_in

To override them all at once, change the global configuration of redirect_url. To change individual URLs, override the appropriate method in your subclassed controller.

These “failure” methods are called for signed out sessions:

  • application#url_after_denied_access_when_signed_out
  • sessions#url_after_destroy

You can override the appropriate method in your subclassed controller or you can set a configuration value for either of these URLs:

  • Clearance.configuration.url_after_denied_access_when_signed_out
  • Clearance.configuration.url_after_destroy

Both configurations default to nil and if not set will default to sign_in_url in sessions_controller.rb and authorization.rb for backwards compatibility.

Views

See app/views for the default behavior.

To override a view, create your own copy of it:

app/views/clearance_mailer/change_password.html.erb
app/views/passwords/create.html.erb
app/views/passwords/edit.html.erb
app/views/passwords/new.html.erb
app/views/sessions/_form.html.erb
app/views/sessions/new.html.erb
app/views/users/_form.html.erb
app/views/users/new.html.erb

You can use the Clearance views generator to copy the default views to your application for modification.

rails generate clearance:views

Layouts

By default, Clearance uses your application’s default layout. If you would like to change the layout that Clearance uses when rendering its views, simply specify the layout in the config/application.rb

config.to_prepare do
  Clearance::PasswordsController.layout "my_passwords_layout"
  Clearance::SessionsController.layout "my_sessions_layout"
  Clearance::UsersController.layout "my_admin_layout"
end

Translations

All flash messages and email subject lines are stored in i18n translations. Override them like any other translation.

See config/locales/clearance.en.yml for the default behavior.

You can also install clearance-i18n for access to additional, user-contributed translations.

User Model

See lib/clearance/user.rb for the default behavior. You can override those methods as needed.

Note that there are some model-level validations (see above link for detail) which the Clearance::User module will add to the configured model class and which may conflict with or duplicate already present validations on the email and password attributes. Over-riding the email_optional? or skip_password_validation? methods to return true will disable those validations from being added.

Signed Cookies

By default, Clearance uses unsigned cookies. If you would like to use signed cookies you can do so by overriding the default in an initializer like so:

Clearance.configure do |config|
  # ... other overrides
  config.signed_cookie = true
end

If you are currently not using signed cookies but would like to migrate your users over to them without breaking current sessions, you can do so by passing in :migrate rather than true as so:

Clearance.configure do |config|
  # ... other overrides
  config.signed_cookie = :migrate
end

You can read more about signed cookies in Clearance and why they are a good idea in the pull request that added them.

app/guards/email_confirmation_guard.rb

class EmailConfirmationGuard < Clearance::SignInGuard def call

if unconfirmed?
  failure("You must confirm your email address.")
else
  next_guard
end

end

def unconfirmed?

signed_in? && !current_user.confirmed_at

end end


## Testing

### Fast Feature Specs

Clearance includes middleware that avoids wasting time spent visiting, loading,
and submitting the sign in form. It instead signs in the designated user
directly. The speed increase can be [substantial][backdoor].

[backdoor]: http://robots.thoughtbot.com/post/37907699673/faster-tests-sign-in-through-the-back-door

Enable the Middleware in Test:

```ruby
# config/environments/test.rb
MyRailsApp::Application.configure do
  # ...
  config.middleware.use Clearance::BackDoor do |username|
    Clearance.configuration.user_model.find_by(username: username)
  end
  # ...
end

Ready Made Feature Specs

If you’re using RSpec, you can generate feature specs to help prevent regressions in Clearance’s integration with your Rails app over time. These feature specs, will also require factory_bot_rails.

To Generate the clearance specs, run:

rails generate clearance:specs

Controller Test Helpers

To test controller actions that are protected by before_action :require_login, require Clearance’s test helpers in your test suite.

For rspec, add the following line to your spec/rails_helper.rb or spec/spec_helper if rails_helper does not exist:

require "clearance/rspec"

For test-unit, add this line to your test/test_helper.rb:

require "clearance/test_unit"

Note for Rails 5: the default generated controller tests are now integration tests. You will need to use the backdoor middleware instead.

This will make Clearance::Controller methods work in your controllers during functional tests and provide access to helper methods like:

sign_in
sign_in_as(user)
sign_out

View and Helper Spec Helpers

Does the view or helper you’re testing reference signed_in?, signed_out? or current_user? If you require 'clearance/rspec', you will have the following helpers available in your view specs:

sign_in
sign_in_as(user)

These will make the clearance view helpers work as expected by signing in either a new instance of your user model (sign_in) or the object you pass to sign_in_as. If you do not call one of these sign in helpers or otherwise set current_user in your view specs, your view will behave as if there is no current user: signed_in? will be false and signed_out? will be true.

About thoughtbot

thoughtbot

This repo is maintained and funded by thoughtbot, inc. The names and logos for thoughtbot are trademarks of thoughtbot, inc.

We love open source software! See our other projects. We are available for hire.


Articles

  • coming soon...