Simple Rails Authentication with Clearance

Share this article

Screenshot 2015-09-16 13.04.04

During the past month I have covered various authentication solutions for Rails. This article is the fifth in the series (oh my) and our guest today is Clearance.

Clearance is an opinionated e-mail/password-based authentication and authorization solution for Rails created by Thoughtbot Inc (the guys who created FactoryGirl, PaperClip and other cool libraries). Clearance is designed as a Rails engine. It is intended to be small, simple, and well-tested. In a sense, it is similar to Devise in that Clearance has many defaults to help you get started in nearly five minutes, and all those defaults can be easily overridden. In contrast to Devise, however, Clearance presents only minimal functionality that can be customized further as you see fit.

This solution is actively maintained, so I really recommend trying it out. In this article I will demonstrate how to integrate Clearance, restrict access, customize it, and use additional checks during sign-in.

Source code can be found on GitHub.

Working demo is available at sitepoint-clearance.herokuapp.com.

Preparations

To start off, create a new Rails app under a codename “Clear Sky”:

$ rails new ClearSky -T

For this demo Rails 4.2 will be used, but Clearance is compatible with Rails 3.2, as well.

If you wish to follow along with how I style the app, add the following gem to your Gemfile to take advantage of Bootstrap’s styles:

Gemfile

[...]
gem 'bootstrap-sass'
[...]

Also modify application.scss file:

stylesheets/application.scss

@import 'bootstrap-sprockets';
@import 'bootstrap';

Now update the layout. You don’t have to add those Bootstrap-specific blocks, but make sure that flash messages are being rendered somewhere because Clearance relies on them to display important information to the user.

layouts/application.html.erb

[...
<nav class="navbar navbar-inverse">
  <div class="container">
    <div class="navbar-header">
      <%= link_to 'Clear Sky', root_path, class: 'navbar-brand' %>
    </div>
    <div id="navbar">

    </div>
  </div>
</nav>

<div class="container">
  <% flash.each do |key, value| %>
    <div class="alert alert-<%= key %>">
      <%= value %>
    </div>
  <% end %>

  <%= yield %>
</div>
[...]

We will also need a basic root page, so create a pages controller and the corresponding route:

pages_controller.rb

class PagesController < ApplicationController
  def index
  end
end

config/routes.rb

[...]
root to: 'pages#index'
[...]

views/pages/index.html.erb

<div class="page-header"><h1>Welcome!</h1></div>

Now everything is ready to add Clearance to our project. Proceed to the next step!

Integrating Clearance

Getting started with Clearance is very easy. First of all drop the gem into your Gemfile:

Gemfile

[...]
gem 'clearance', '~> 1.11'
[...]

Now, run a special generator and apply migrations:

$ rails generate clearance:install
$ rake db:migrate

This generator does the following:

  • Creates a new clearance.rb file inside the initializers directory.
  • Creates a new User model, migration file, and adds the line include Clearance::User to it. This model will have the following attributes:
    • email (string)
    • encrypted_password (string)
    • confirmation_token (string)
    • remember_token (string)
    • Basic attributes (id, created_at, updated_at)
  • Adds include Clearance::Controller into the ApplicationController. This way the controllers will have special Clearance methods.

If you already have a User model, it will be modified accordingly. If you don’t want to call your model User, modify the config.user_model setting inside the clearance.rb initializer file. All in all, this file is the first place to tweak Clearance’s settings – for the full list of them refer to this section in the docs.

Note that even though confirmation_token is present, it is not being used. Creating a user simply means adding a new record to the users table and signing that user into the app. So, if you want to ensure that e-mail is confirmed before the account can be used, additional steps need to be taken. In the following sections we will discuss how to customize Clearance and perform additional sign-in checks in a more detail.

After running Clearance’s generator, a small todo list will be printed out in the console, so make sure you have completed all the required steps. If you are following along, only one additional action has to be done:

config/environments/development.rb

[...]
config.action_mailer.default_url_options = { host: 'localhost:3000' }
[...]

For a production environment, add settings that work for you.

Note that you will probably want to modify the sender’s e-mail address, as well:

config/initializers/clearance.rb

[...]
config.mailer_sender = 'reply@example.com'
[...]

Clearance is now up and running, so we can add “Log In” and “Sign Out” menu items:

layouts/application.html.erb

[...]
<div id="navbar">
  <% if signed_in? %>
    <ul class="nav navbar-nav">
      <li><%= link_to 'Add Page', new_page_path %></li>
    </ul>
  <% end %>

  <ul class="nav navbar-nav pull-right">
    <% if signed_in? %>
      <li><span><%= current_user.email %></span></li>
      <li><%= link_to 'Sign out', sign_out_path, method: :delete %></li>
    <% else %>
      <li><%= link_to 'Sign in', sign_in_path %></li>
    <% end %>
  </ul>
</div>
[...]

signed_in? and current_user are helper methods provided by Clearance that are pretty self-explanatory. You can also use the signed_out? method.

The sign_out_path and sign_in_path routes are also created by Clearance – we will discuss them a bit more in the next section.

Restricting Access

Now as we added the basic authentication system, you probably want to restrict access to some pages of the website. That is really easy to do. Suppose, we have a new action inside the PagesController:

pages_controller.rb

[...]
def new
end
[...]

config/routes.rb

[...]
resources :pages, only: [:new]
[...]

views/pages/new.html.erb

<div class="page-header"><h1>Add Page</h1></div>

To allow only authenticated users to access this page, simply add a before_action:

pages_controller.rb

before_action :require_login, only: [:new]

Now, if an unauthenticated user tries to access this route, they will be redirected to the “Log In” page. To change this behavior, override the url_after_denied_access_when_signed_out method in your ApplicationController and return a route of your choice. Read more here.

Clearance also provides routing constraints that can come in handy. For example, if I wanted to define a special root route for all authenticated users, I’d use the following constraints:

config/routes.rb

[...]
constraints Clearance::Constraints::SignedIn.new do
  root to: 'pages#new', as: :signed_in_root
end

constraints Clearance::Constraints::SignedOut.new do
  root to: 'pages#index'
end
[...]

Here, all authenticated users will have pages#new as the root page. For guests, pages#index will be the root. Please note that if you define two root routes, one of them has to be named, otherwise an error will be raised.

Customizing Clearance

You are probably wondering how to customize Clearance further, for example how to modify views, controllers’ actions or routes. Well, that’s pretty simple as well.

Let’s start with routes. Run the following command to copy the default routes into your routes.rb file:

$ rails generate clearance:routes

This command will also set the config.routes setting to false, meaning that custom routes will be used.

Inside the routes.rb file, you will see some new lines of code:

config/routes.rb

[...]
resources :passwords, controller: "clearance/passwords", only: [:create, :new]
resource :session, controller: "clearance/sessions", only: [:create]

resources :users, controller: "clearance/users", only: [:create] do
  resource :password,
           controller: "clearance/passwords",
           only: [:create, :edit, :update]
end

get "/sign_in" => "clearance/sessions#new", as: "sign_in"
delete "/sign_out" => "clearance/sessions#destroy", as: "sign_out"
get "/sign_up" => "clearance/users#new", as: "sign_up"
[...]

Feel free to modify these as needed.

To override controllers’ methods, create a new controller and subclass it from one of the existing ones: Clearance::PasswordsController, Clearance::SessionsController or Clearance::UsersController. Now you can redefine methods as you see fit. Just don’t forget to update the routes to point to your new controller.

Modifying views is simple, as well. Run:

$ rails generate clearance:views

to copy all the default views in your views folder and change them as you see fit.

By default Clearance is going to use your application’s layout, but this can be changed as well. If you need a custom layout to be rendered for one of the controllers, add the following code to the initializer file:

config/initializers/clearance.rb

[...]
Clearance::PasswordsController.layout 'my_passwords_layout'
Clearance::SessionsController.layout 'my_sessions_layout'
Clearance::UsersController.layout 'my_admin_layout'
[...]

When you copy the default views using the command shown above, the I18n file will be copied as well. Use it to change translations, as necessary.

The default User model has a bunch of methods that can be redefined, too.

Additional Sign In Checks

By default, Clearance only checks the user’s e-mail and password when authenticating. Suppose, however, that account is suspended and we don’t want to allow those users to login. This can be implemented with so-called “sign-in guards”.

First of all, add a new field to your users table:

$ rails g migration add_suspended_to_users suspended:boolean

Modify the migration:

xxx_add_suspended_to_users.rb

class AddSuspendedToUsers < ActiveRecord::Migration
  def change
    add_column :users, :suspended, :boolean, default: false, index: true
  end
end

and apply it:

$ rake db:migrate

Now, open the initializer file and change it, like so:

config/initializers/clearance.rb

class SuspendedCheckGuard < Clearance::SignInGuard
  def call
    if suspended?
      failure("Your account is suspended.")
    else
      next_guard
    end
  end

  def suspended?
    current_user.suspended?
  end
end

Clearance.configure do |config|
  config.sign_in_guards = [SuspendedCheckGuard]
  [...]
end

Feel free to extract SuspendedCheckGuard to another file.

The idea behind SignInGuard is pretty simple: it checks a stack of conditions before signing in a user. Each guard is run in order and hands the session off to the next guard in the stack.

SignInGuard responds to a call method. It is initialized with a session and the current stack. On success, a guard should call the next guard or return SuccessStatus.new if you don’t want any subsequent guards to run. On failure, a guard should call FailureStatus.new(failure_message).

Clearance provides the SignInGuard base class that can be inherited. This class already implement methods like signed_in? and current_user.

In our example we define the call method that checks whether the user’s account is suspended. If yes – set the failure message and forbid login. This message will be displayed in the flash. If no – run the next check if it is present in the stack. Once all checks are run successfully, the user is logged in.

Now you can boot your server and check how the app is working!

Conclusion

In this article we discussed Clearance – an opinionated authentication and authorization system. I encourage you to browse the project’s wiki as it has entries explaining how to customize Clearance further. I think that this library is a great alternative to Devise if you need to quickly start off and do not need all the features Devise provides.

Have you ever used Clearance? Would you consider using it in future? Share your opinion!

As always, I thank you for staying with me and see you soon!

Frequently Asked Questions (FAQs) about Rails Authentication with Clearance

How do I install the Clearance gem in my Rails application?

To install the Clearance gem in your Rails application, you need to add the gem to your Gemfile. Open your Gemfile and add the following line: gem 'clearance'. Then, run bundle install in your terminal to install the gem. After the gem is installed, you need to run rails generate clearance:install to generate the necessary files and migrations. Finally, run rails db:migrate to apply the migrations to your database.

How do I customize the Clearance views?

Clearance provides a set of default views for authentication. However, you can customize these views to fit your application’s needs. To do this, run rails generate clearance:views. This will copy the default views to your application, allowing you to modify them as needed.

How do I configure Clearance to use a custom user model?

By default, Clearance uses a User model for authentication. If you want to use a different model, you can configure Clearance to do so. In your config/initializers/clearance.rb file, set the Clearance.configure block to use your custom model. For example, if you have a Member model, you would set config.user_model = Member.

How do I add additional fields to the Clearance user model?

If you need to add additional fields to the User model, you can do so by creating a new migration. For example, if you want to add a first_name and last_name field, you would run rails generate migration AddNameToUsers first_name:string last_name:string. Then, run rails db:migrate to apply the migration.

How do I restrict access to certain pages with Clearance?

Clearance provides a require_login method that you can use to restrict access to certain pages. In your controller, you can add a before_action callback to call this method. For example, before_action :require_login, only: [:edit, :update] would restrict access to the edit and update actions to logged-in users.

How do I test Clearance in my Rails application?

Clearance provides a set of helpers that you can use in your tests. To use these helpers, include Clearance::Test::ControllerHelpers in your test file. Then, you can use methods like sign_in and sign_out to simulate user authentication in your tests.

How do I change the default Clearance routes?

Clearance generates a set of default routes for authentication. If you want to change these routes, you can do so in your config/routes.rb file. For example, you could change the sign in route to /login by adding get '/login' => 'clearance/sessions#new' to your routes file.

How do I use Clearance with Rails API?

If you’re building a Rails API, you can still use Clearance for authentication. However, you’ll need to configure Clearance to use API mode. In your config/initializers/clearance.rb file, set config.api = true.

How do I upgrade Clearance in my Rails application?

To upgrade Clearance, you need to update the gem in your Gemfile. Change the version number to the latest version and run bundle update clearance. Then, check the Clearance GitHub page for any necessary migration or configuration changes.

How do I uninstall Clearance from my Rails application?

To uninstall Clearance, remove the gem from your Gemfile and run bundle install. Then, remove any Clearance-related code from your application, including migrations, models, controllers, and views. Finally, remove the Clearance initializer from your config/initializers directory.

Ilya Bodrov-KrukowskiIlya Bodrov-Krukowski
View Author

Ilya Bodrov is personal IT teacher, a senior engineer working at Campaigner LLC, author and teaching assistant at Sitepoint and lecturer at Moscow Aviations Institute. His primary programming languages are Ruby (with Rails) and JavaScript. He enjoys coding, teaching people and learning new things. Ilya also has some Cisco and Microsoft certificates and was working as a tutor in an educational center for a couple of years. In his free time he tweets, writes posts for his website, participates in OpenSource projects, goes in for sports and plays music.

GlennG
Share this article
Read Next
Get the freshest news and resources for developers, designers and digital creators in your inbox each week