Github Authentication in Ruby on Rails
This article will show you how to add Github authentication to your Rails app.
Published on:June 9, 2016
Introduction
In this article we will show you how to implement Github authentication in your Ruby on Rails application. This allows your users to seamlessly sign on to your application without you having to store sensitive information such as passwords. Let's get started.
Github Setup
Before we can start building our Rails application, we must create an oauth2 application under Github. Doing so is easy, simply follow the steps listed below.
-
First, visit https://github.com/settings/developers. You should see the screen listed below.
-
Next, click either of the buttons that say Register a new application. The screen below should appear.
- Fill in your application details . For Authorization callback URL use
http://localhost:3000/auth/github/callback
. When you click Register Application you will be taken to the screen below. Make note of the Client ID and Client Secret. (not the ones in the screenshot, those are for example only and are not valid). You will use those when building your Rails application.
Great! Now we are ready to build our Rails application.
Rails Application Setup
The first thing we need to do is add the omniauth-github gem to our gemfile. This gem implements the oauth2 protocol for single sign on to github. Open your Gemfile now and add in the code listed below.
gem 'omniauth-github'
Great, Now run a bundle install to install the gem.
bundle install
Now we need to add an initializer called omniauth.rb
. This initializer will initialize the Omniauth Github provider. Create a file called omniauth.rb in your config/initializers
folder and add in the code listed below.
opts = { scope: 'user:email' }
Rails.application.config.middleware.use OmniAuth::Builder do
provider :github, Rails.application.secrets.github_client_id, Rails.application.secrets.github_client_secret, opts
end
Now let's add our client ID and secret we took note of earlier to the config/secrets.yml
file. Before you do this, you should add config/secrets.yml to your .gitignore
file to ensure you don't accidentally commit it to git. Open up the secrets.yml file and modify it so it looks like the code listed below, replacing the example values with your client id and secret.
development:
secret_key_base: e839e2cc3c9e9977b5765bd3dfcabcc944c33a4d5776a58d32b2150e760b22a9649eeba7dd25e7aff50d76218b66bb48e98823e66b6732e0f6546caf34bec27a
github_client_id: Your Github client id
github_client_secret: Your Github client secret
test:
secret_key_base: 8773c1ca845f1512dcbb6fdc2956eb1b87b053c563a3279dfaf74e82ed1cd481ee3949cbd4f1ebda087fffa4fafa98315507f1e4dfb9b1619d30fd52cf8a7e3c
# Do not keep production secrets in the repository,
# instead read values from the environment.
production:
secret_key_base: <%= ENV["SECRET_KEY_BASE"] %>
You'll notice that we didn't fill out values for test and production. This is because Github only supports 1 callback URL, so we must create a new application for each environment.
Great, now let's create a model called User. This model will store the fields github provides us, and will also contain the business logic for signing in. Run the command below to create the user model now.
rails g model User username avatar_url email uid provider oauth_token
Next run a rake db:migrate to migrate the database.
rake db:migrate
Next, create a new controller called SessionsController. This controller will handle logging in and logging out. Run the command below to create this controller now.
rails g controller sessions new create destroy
Now we need to update our routes file to add in omniauth specific routes along with a root path. Open up your config/routes.rb
file now and modify it so that it looks like the code listed below.
Rails.application.routes.draw do
get "/auth/:provider/callback", to: "sessions#create"
get 'auth/failure', to: redirect('/')
delete 'signout', to: 'sessions#destroy', as: 'signout'
root to: 'sessions#new'
end
Next we need to add some code to our user model to tell our rails app how to parse the data that omniauth provides. Open up your app/models/user.rb
file and modify it so it looks like the code listed below.
class User < ActiveRecord::Base
def self.from_omniauth(auth)
where(provider: auth.provider, uid: auth.uid).first_or_initialize.tap do |user|
user.email = auth.info.email
user.uid = auth.uid
user.provider = auth.provider
user.avatar_url = auth.info.image
user.username = auth.info.name
user.oauth_token = auth.credentials.token
user.save!
end
end
end
The self.from_omniauth
method above will attempt to find the given user based on the provider and uid. If it can't find a user matching that information, it will create a new entry. All fields are updated with the latest information and the user is saved.
Great, now we need to add some code to our Sessions controller. Open up the app/controllers/sessions_controller.rb
file now and add in the code listed below.
class SessionsController < ApplicationController
def new
end
def create
user = User.from_omniauth(env["omniauth.auth"])
if user.valid?
session[:user_id] = user.id
redirect_to request.env['omniauth.origin']
end
end
def destroy
reset_session
redirect_to request.referer
end
end
Great, now we need to create a method called current_user
. The current user method will return the currently logged in user or nil if the user isn't logged in. We will create this method in our Application controller and share it with our views by declaring it to be a helper_method
. Open up your app/controllers/application_controller.rb
file and modify it so that it looks like the code listed below.
class ApplicationController < ActionController::Base
protect_from_forgery with: :exception
helper_method :current_user
def current_user
session[:user_id].nil? ? nil : User.find(session[:user_id])
end
end
Next we need to add some code to our New view for our Sessions controller. Open up the app/views/sessions/new.html.erb
file and modify it so that it looks like the code listed below.
<% if current_user.blank? %>
<h1>Please Sign In</h1>
<%= link_to 'Sign In with Github', '/auth/github' %>
<% else %>
<p>
You are signed in as <%= current_user.username %>. Click the button below to sign out.
</p>
<%= button_to "Sign Out", signout_path, method: :delete %>
<% end %>
Now if you start a rails server
and open up chrome to your Rails development server you'll see that you can sign in and out of Github. That's it! That's all there is to it!
As always, if you have any questions, comments, or feedback, please feel free to leave a comment below. If you want to support us, please consider purchasing a Pro membership as it helps us continue to provide high quality content. Thanks for reading!