Omniauth without Devise
Previously I’ve covered Github omniauth with Devise, and only github omniauth with Devise (without email-based 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 gem omniauth
gems:
# Gemfile
gem 'omniauth-github', github: 'omniauth/omniauth-github', branch: 'master'
gem "omniauth-rails_csrf_protection", "~> 1.0"
If you are using Github omniauth, you can generate API credentials here
For development environment you can use
Homepage URL:
http://localhost:3000
Authorization callback URL
http://localhost:3000/auth/github/callback
Add your social provider API credentials to the Rails app:
# echo > config/initializers/omniauth.rb
# config/initializers/omniauth.rb
Rails.application.config.middleware.use OmniAuth::Builder do
provider :github, "GITHUB_ID", "GITHUB_SECRET"
end
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
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'
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 makecurrent_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
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 %>
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
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
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
That’s it! Now you can use omniauth without devise!