Omniauth without Devise
Yaroslav Shmarov

Yaroslav Shmarov @superails

About: I write about different Ruby on Rails topics. Check it out!

Location:
Chernihiv, Ukraine
Joined:
Nov 4, 2017

Omniauth without Devise

Publish Date: Feb 7 '23
6 4

Previously I’ve covered Github omniauth with Devise, and Github omniauth with Devise without email registration.

An even simpler solution would be to sign in via a social login provider without Devise at all! Here’s the easiest way to do it.

First, add the omniauth gems:

# Gemfile
gem 'omniauth-github', github: 'omniauth/omniauth-github', branch: 'master'
gem "omniauth-rails_csrf_protection", "~> 1.0"
Enter fullscreen mode Exit fullscreen mode

Add your social provider API credentials:

# https://github.com/omniauth/omniauth
# https://github.com/settings/applications/new
# echo > config/initializers/omniauth.rb
# config/initializers/omniauth.rb
Rails.application.config.middleware.use OmniAuth::Builder do
  provider :github, "GITHUB_ID", "GITHUB_SECRET"
end
Enter fullscreen mode Exit fullscreen mode

Create a user model. We will also add a few static pages:

  • /landing_page that can be accessed without authentication
  • /dashboard that requires authentication
rails g controller static_pages landing_page dashboard
rails g model User email github_uid
Enter fullscreen mode Exit fullscreen mode

Routes:

# config/routes.rb
  root 'static_pages#landing_page'
  get 'dashboard', to: 'static_pages#dashboard'

  get 'auth/github/callback', to: 'sessions#create'
  delete 'logout', to: 'sessions#destroy'
  # get 'login', to: redirect('/auth/github'), as: 'login'
Enter fullscreen mode Exit fullscreen mode

Gems like devise provide some default methods, that we will have to add on our own now:

  • def current_user - get the current user from session params.
  • def user_signed_in? - check if there is a current user.
  • def require_authentication - to restrict controller actions for non-authenticated users.
  • helper_method :current_user - to make current_user available in views.
# app/controllers/application_controller.rb
class ApplicationController < ActionController::Base
  protect_from_forgery with: :exception
  helper_method :current_user

  def require_authentication
    redirect_to root_path, alert: 'Requires authentication' unless user_signed_in?
  end

  def current_user
    @current_user ||= User.find(session[:user_id]) if session[:user_id]
  end

  def user_signed_in?
    # converts current_user to a boolean by negating the negation
    !!current_user
  end
end
Enter fullscreen mode Exit fullscreen mode

The button to /auth/github will redirect to the github login page.

# app/views/layouts/application.html.erb
<%= link_to 'Home', root_path %>
<% if current_user %>
  <%= current_user.email %>
  <%= link_to 'Dashboard', dashboard_path %>
  <%= button_to 'Logout', logout_path, method: :delete, data: { turbo: false } %>
<% else %>
  <%= button_to "Sign in with Github", "/auth/github", data: { turbo: false } %>
<% end %>
Enter fullscreen mode Exit fullscreen mode

After successful authentication, the user should be redirected to sessions#create with request.env['omniauth.auth'].

# app/controllers/sessions_controller.rb
class SessionsController < ApplicationController
  def create
    @user = User.from_omniauth(request.env['omniauth.auth'])
    if @user.persisted?
      session[:user_id] = @user.id
      redirect_to dashboard_path, notice: "Logged in as #{@user.email}"
    else
      redirect_to root_url, alert: 'Failure'
    end
  end

  def destroy
    session[:user_id] = nil
    redirect_to root_path
  end
end
Enter fullscreen mode Exit fullscreen mode

from_omniauth will find the users email and uid in the data provided by github, and find or create the user.

# app/models/user.rb
class User < ApplicationRecord
  validates :github_uid, presence: true, uniqueness: true
  validates :email, format: { with: URI::MailTo::EMAIL_REGEXP }, presence: true, uniqueness: true

  def self.from_omniauth(access_token)
    github_uid = access_token.uid
    data = access_token.info
    email = data['email']

    User.find_or_create_by(email:, github_uid:)
  end
end
Enter fullscreen mode Exit fullscreen mode

Finally, require authentication to visit /dashboard:

# app/controllers/static_pages_controller.rb
class StaticPagesController < ApplicationController
  before_action :require_authentication, only: :dashboard

  def landing_page
  end

  def dashboard
  end
end
Enter fullscreen mode Exit fullscreen mode

That’s it! Now you can use omniauth without devise!

Comments 4 total

  • Ahmed Nadar
    Ahmed NadarFeb 8, 2023

    Nice article as usual.
    I have noticed many apps are using different authanitcation way these days.
    Do you think Rails apps should implement authanitcations without Devise

    • Yaroslav Shmarov
      Yaroslav ShmarovFeb 9, 2023

      It really depends on what you are building. For many cases omniauth-only would be enough.

      Sometimes, getting a confirmed email address can be much more valuable, than having an omniauth user account.

      I think that devise via email/password + omniauth still stays the most versatile approach.

  • Ivo Di
    Ivo DiFeb 16, 2023

    After trying an official omniauth and devise and omniauth-google-oauth2 docs i couldn't make it all working. But thanks for your article I finally did what I wanted.
    ❤️

Add comment