What is Authentication ?
I guess you already know what authentication is. But if you have been living under a rock since the last decade: Authentication basically is a method to grant access to users who are using your app by verifying the identity of the user. This can be done by providing credentials like username, email and password to each unique user. There are simple as well as complex authentication methods that can be implemented in your app; simple as in using just email and password for authentication and an example of a complex authentication method will be SSO (or Single Sign On). With SSO, authentication lives on a separate app or API server and multiple apps and services can be authenticated using just a single account.
Devise
Devise is the most popular and flexible gem for authentication in your rails apps. I guess you have already come across this gem every now and then. But, if you are an absolute beginner to rails, let me show you how to use devise to add authentication to you rails app.
Devise Github Page: https://github.com/heartcombo/devise
Getting started with Devise
In this tutorial, i’ll creating a demo app to show you the basics on authentication with devise. To get started, add devise to your Gemfile and run bundler.
#File: Gemfile
gem 'devise'
bundle install
Install Devise using the generator
Devise comes with generators to install, create user models and also to generate views. To install devise using the provided generator, run the following command
rails g devise:install
User model
Now create a new user model using the generator, ‘user’ is the model name here.
rails g devise user
Migrations
Now run the migrations, This will create a new table called ‘users’ with the following columns that you can see below.
rails db:migrate
Devise Views
If you don’t want to create your own views, devise also comes with views. You can generate devise views and customize it however you like. To generate devise views run the following command.
rails g devise:views
Login Page
Now run rails server and when you open http://localhost:3000/users/sign_in in a web browser, you should be able to see the login page
rails s
Testing our Authentication
To test out my authentication i’ll add a new controller called ‘pages’ and a new index page
rails g controller pages index
Root route
And also i will set the root route of my app to pages#index, so that every time when i open http://localhost:3000 or the root route of my app, it will redirect to pages#index page.
#File: config/routes.rb
Rails.application.routes.draw do
root to: 'pages#index'
get 'pages/index'
devise_for :users
end
Pages Index View
In my Pages’ index view. I added the following to show the current signed in user’s email & ID, if the user is signed in. And also i added links to the signup and signin page, as well as a link to the signout path.
#File: app/views/pages/index.html.erb
<h1>Pages#index</h1>
<hr>
<% if signed_in? %>
<p>Signed In as: <%= current_user.email %></p>
<p>Logout: <%= link_to "Sign out", destroy_user_session_path, method: :delete, data: { confirm: 'Are you sure?'} %></p>
<% else %>
<p>Not Signed In</p>
<p>Vist Signin Page: <%= link_to "Sign in", new_user_session_path %></p>
<p>Vist Signup Page: <%= link_to "Sign up", new_user_registration_path %></p>
<% end %>
Devise Mailer
When users request for a password reset or when confirming new user accounts, devise will send password reset links and confirmation links via email. For that we need to configure our action mailer as well as set up the devise mailer URLs, we need to do this for each environment.
Action Mailer: Default URL options
Open your development environment config file and add the following config.
#File: config/environments/development.rb
Rails.application.configure do
#...Other configs...
config.action_mailer.default_url_options = { host: 'localhost', port: 3000 }
#...Other configs...
end
Using letter_opener in development
The letter_opener gem is a really useful gem that can be used in development environment to view the outgoing mails. In this case we will be using letter_opener to view the mails sent by devise. To use letter_opener, add letter opener to your Gemfile and run bundler
#File: Gemfile
gem 'letter_opener'
bundle install
In your development environment i.e; config/environments/development.rb add the following config to use letter opener.
#File: config/environments/development.rb
Rails.application.configure do
#...Other configs...
#...For letter opener start...
config.action_mailer.delivery_method = :letter_opener
config.action_mailer.perform_deliveries = true
#...for letter opener end...
config.action_mailer.default_url_options = { host: 'localhost', port: 3000 }
#...Other configs...
end
Mail Preview With Letter Opener
Whenever devise sends mail for confirmations, password resets, etc; letter opener will open the generated mail in a new browser window automatically.
Sending Mails In Production
When you run your app in production, the default action mailer URL will be the domain name or hostname of your app/app server. For example; if you are using heroku, it will be “https://yourappname.herokuapp.com”
#File: config/environments/production.rb
Rails.application.configure do
#...Other configs...
config.action_mailer.default_url_options = { :protocol => 'https', :host => 'yourappname.herokuapp.com' }
#...Other configs...
end
Sending Mails With SMTP
To send and view outgoing mails in development environment, we can use the ‘letter_opener’ gem. But, to send outgoing mails in production environment, we have to configure action mailer to send mails using SMTP. If you want to send mails using SMTP, you can get a free account from sendgrid or other SMTP providers. If you are using heroku you can add it to your app from heroku elements. Make sure to add the SMTP credentials in your environment variables.
#File: config/environments/production.rb
Rails.application.configure do
#...Other Configs...
config.action_mailer.delivery_method = :smtp
config.action_mailer.smtp_settings = {
:address => ENV['SMTP_SERVER'],
:port => ENV['SMTP_PORT'],
:user_name => ENV['SMTP_USERNAME'],
:password => ENV['SMTP_PASSWORD'],
:authentication => :login,
:tls => :true,
:enable_starttls_auto => true
}
#...Other Configs...
end
Mail sender address
Also, we need to configure the default mail sender address in config/initializers/devise.rb
#File: config/initializers/devise.rb
Devise.setup do |config|
##..Other configs...
config.mailer_sender = '[email protected]'
##..Other configs...
end
Devise Helpers
Devise comes with a bunch of helpers that can be used to check if user is logged in, check current user’s details etc.
To check/verify if a user is signed in, use the following helper:
user_signed_in?
signed_in?
Example;
<% if signed_in? %>
Do this
<% else %>
Do that
<% end %>
Another example; with pundit authorization
def index
unless signed_in?
redirect_to new_user_session_path
else
authorize Book
end
end
For the currently signed in user, you can use
current_user
Example;
Currently Logged In As: <%= current_user.email %>
Or when using with pundit
def initialize(current_user, book)
@current_user = current_user
@book = book
end
def create?
@current_user.admin?
end
Please read Devise’s documentation here, to get the complete list of helpers and how to use them.
https://github.com/heartcombo/devise
Devise Routes
Here’s the list of routes that comes with devise, you can use these routes wherever you want to add sign up/sign in links in your app. You can run rails routes to get the list of routes.
rails routes
Checkout This Demo App On Github
Check out my demo app on github, if you want to test out authentication with devise. Visit the following link to do so.
Github Link: https://github.com/railshero/Devise-auth-demo
Final Thoughts
There are also many other gems that we can use to add authentication to our app, with gems like authlogic, doorkeeper, omni auth, etc. And we can even create our own authentication functionality from scratch. And for using advanced methods with devise or customizing it, please read devise’s documentation. https://www.rubydoc.info/gems/devise/2.2.8