Authentication with Devise

Roy van de Water

Covered in this presentation:

Helpful Links



Project on Github:

Basic Setup

  1. Add devise to Gemfile
  2. Run Devise installation generator
                      rails g devise:install
  3. Add your action mailer default host configuration to the appropriate environments
                        config.action_mailer.default_url_options = { :host => 'localhost:3000' }
  4. Define your homepage in the routes file
                      root :to => "static#index"
  5. Add the alert and notice flash messages to your application layout

    <%= notice %>

    <%= alert %>

  6. Run Devise generator:
                      rails g devise user

Handy Helpers

              <% unless user_signed_in? -%>
  • <%= link_to "Sign in", new_user_session_path %>
  • <% else -%>
  • <%= link_to "Sign out", destroy_user_session_path %>
  • <% end -%>
                  before_filter :authenticate_user!

    Email Verification

    To require email confirmation, uncomment the following lines from the devise migration:

                  # Rails.root/db/migrations/2011011620391_devise_create_users.rb
                  def self.up
                    create_table(:users) do |t|
                    add_index :users, :confirmation_token,   :unique => true

    And add ":confirmable" to the devise line in your user model:

                  # Rails.root/app/models/user.rb
                  devise :database_authenticatable, :registerable,
                         :recoverable, :rememberable, :trackable, :validatable,

    Then rerun your migrations and you're done

    Note: The development server must be restarted to recognize "user_confirmation_url" as a valid path

    Custom Views

    By default, devise uses its own views, located inside the gem.

    To use custom sign in and new user registration forms run the following devise generator:

                  rails g devise:views

    This pulls in all devise views, allowing them to be changed.

    Note: You can overwrite only the views you want to update. Missing views will automatically be retrieved from the gem

    Custom Actions

    To execute custom code on login/logout, override the sessions controller:

                    # Rails.root/app/controllers/sessions.rb
                    class SessionsController < Devise::SessionsController
                      def create
               "Attempt to sign in by #{ params[:user][:email] }"
                      def destroy
               "#{ } signed out"

    And point the devise routes line at your new controller:

                  # Rails.root/config/routes.rb
                  devise_for :users, :controllers => { :sessions => :sessions }

    The views for the overwritten controller must be copied locally into apps/views/sessions

    Custom Encryptor

    Create your own custom encryptor in the lib directory of the rails app:

                # Rails.root/lib/devise/encryptors/rot13.rb
                module Devise
                  module Encryptors
                    class Rot13 < Base
                      def self.digest(password, stretches, salt, pepper)
                        "#{password}-#{salt}".tr! "A-Za-z", "N-ZA-Mn-za-m"

    Then require and select your new encryptor in the Devise initializer

                # Rails.root/config/initializers/devise.rb
                require "devise/encryptors/rot13"
                Devise.setup do |config|
                  config.encryptor = :rot13

    Token Authenticatable

    To enable token authentication uncomment the following lines from the devise migration:

                  # Rails.root/db/migrations/2011011620391_devise_create_users.rb
                  def self.up
                    create_table(:users) do |t|

    And add ":token_authenticatable" to the devise line in your user model:

                  # Rails.root/app/models/user.rb
                  devise :database_authenticatable, :registerable,
                         :recoverable, :rememberable, :trackable, :validatable,

    The authentication token can be generated using


    The user can now authenticate himself like this:
    or by passing the auth_token as the username in HTTP Basic Auth

    Single Access Token

    Authentication tokens are permanent by default

    To create a single access token, clear or reset it on token login

    Devise adds the instance method after_token_authentication to the user model and calls it after every successful token login

    To clear the authentication token, add the following to the user model:

                  def after_token_authentication
                    update_attributes :authentication_token => nil

    To reset the authentication, use the built in token reset method:

                  def after_token_authentication

    Using HTTP Basic Auth

    Devise disables basic auth by default

    To enable, uncomment the following line from config/initializers/devise.rb and set its value to true (and restart the server):

                  config.http_authenticatable = true

    To test if devise is now accepting HTTP Basic Auth, try the following curl statement:

                  curl -u http://localhost:3000/users

    Simple Administrative Access

    Add a boolean to the user model

                class AddIsAdminToUsers < ActiveRecord::Migration
                  def self.up
                    add_column :users, :is_admin, :boolean

    And add a before filter to whatever actions require admin access

                # In controller
                before_filter :require_admin!, :except => [:index, :show]
                # In application controller
                def require_admin!
                  unless current_user.try :is_admin?
                    redirect_to root_path, :alert => "Access Denied"

    Note: For more complex permissions, including permit and restriction functionality, take a look at cream

    Dual User Roles

    Run the devise generator for your second user type

                rails g devise employee

    The employee user now has his own login path, found at new_employee_session_path

    Additionaly helpers include employee_signed_id?, current_employee and the authenticate_employee! before filter

    Actions that need to allow either user type can use the following before filter:

                # In the controller
                before_filter :require_user_or_employee!
                # In the application controller
                def require_user_or_employee!
                  unless user_signed_in? or employee_signed_in?
                    redirect_to root_path, :alert => "Access Denied"

    Login with email or username

    Add the username attribute to the user model:

                rails g add_username_to_users username:string  

    Override the find_for_database_authentication method in the user controller:

                def self.find_for_database_authentication(conditions)
                  login = conditions.delete(:login)
                  .where(["username = :login OR email = :login", 
                         {:login => login}])

    Uncomment the config.authentication_keys line in the devise initializers and replace :email with :login

                config.authentication_keys = [ :login ]

    Add the login as an attr_accessor on the user model

                attr_accessor :login 

    Login with email or username (Part 2)

    Update the registration and login view (remember to run the devise:views generator)

                  # app/views/devise/sessions/new.html.erb

    <%= f.label :login %>
    <%= f.text_field :login %>

    # app/views/devise/registrations/new.html.erb

    <%= f.label :username %>
    <%= f.text_field :username %>

    Login from anywhere on the site

    Add a login form that posts to the user_sessions_path

    <%= form_for(:user, :url => user_session_path) do |f| %>
        <%= f.label :email %>
        <%= f.text_field :email %>
        <%= f.label :password %>
        <%= f.password_field :password %>
        <%= f.submit "Sign in" %>
    <% end %>


    Those Helpful Links Again



    Project on Github: