Here is an ultimate working guide of how to implement authorization with GitHub and define necessary secret keys to development, CI/CD and deployment on Render.com for your Ruby on Rails App.
Before starting to work on this feature make sure you've already implemented Devise in your app and you have sign-in/sign-out user accounts. Always start with an issue and a new branch.
1. Add gems to your Gemfile
:
gem "omniauth-github"
gem "omniauth-rails_csrf_protection"
gem "dotenv"
Run bundle install
.
2. In your config/initializers/devise.rb
find this line of code:
# config.omniauth :github, 'APP_ID', 'APP_SECRET', scope: 'user,public_repo'
Replace with this:
config.omniauth :github, ENV.fetch("MY_GITHUB_ID"), ENV.fetch("MY_GITHUB_SECRET"), scope: "user"
I strongly recommend to avoid the GITHUB_
prefix for secret names because later you will run into troubles when you add secret keys to your GitHub repository. GitHub reserves this prefix for its internal use. That's why I start my names with MY_
.
3. Register your app on GitHub here. Go to the “OAuth” tab and click on “Register a new application”.
On the next screen, fill in the “Application name”, the “Homepage URL” and the “Authorization callback URL”.
For now enter your live app preview’s URL (not your codespace’s):
https://<your-live-application-preview-url>
in the “Homepage URL”, and:
https://<your-live-application-preview-url>/users/auth/github/callback
in the “Authorization callback URL”.
If you're working locally enter the following:
http://localhost:3000/
http://localhost:3000/users/auth/github/callback
On the next screen, you will see your Client ID
, which is your first ENV "MY_GITHUB_ID"
. Also click to Generate a new client secret
to get the second one for "MY_GITHUB_SECRET"
.
4. In the root of your app create .env
and paste your secret keys:
MY_GITHUB_ID="<your-client-id>"
MY_GITHUB_SECRET="<your-client-secret>"
There in the root I also recommend to create env_test.rb
and paste the following code:
require "dotenv/load"
pp ENV.fetch("MY_GITHUB_ID")
pp ENV.fetch("MY_GITHUB_SECRET")
Run ruby env_test.rb
to make sure you set the keys correctly.
5. Now it's time to add new columns to your Users
table.
Run migration:
rails generate migration AddOmniauthAndGithubAccessTokenToUsers
Fill the new migration file in with:
class AddOmniauthAndGithubAccessTokenToUsers < ActiveRecord::Migration[7.1]
def change
add_column :users, :github_access_token, :string
add_column :users, :provider, :string
add_column :users, :uid, :string
end
end
Run rails db:migrate
.
6. Add new route to your config/routes.rb
:
Rails.application.routes.draw do
devise_for :users, controllers: {
omniauth_callbacks: "omniauth_callbacks",
}
end
7. Create new controller app/controllers/omniauth_callbacks_controller.rb
and paste this code there:
class OmniauthCallbacksController < Devise::OmniauthCallbacksController
def github
@user = User.from_omniauth(request.env["omniauth.auth"].except!(:extra))
if @user.persisted?
sign_in_and_redirect @user
set_flash_message(:notice, :success, kind: "GitHub") if is_navigational_format?
else
session["devise.github_data"] = request.env["omniauth.auth"].except!(:extra)
redirect_to root_url, alert: "Something went wrong."
end
end
end
8. Add the following to your app/models/user.rb
devise :omniauthable, omniauth_providers: %i[github]
def self.from_omniauth(auth)
find_or_create_by(provider: auth.provider, uid: auth.uid) do |user|
user.email = auth.info.email
user.password = Devise.friendly_token[0, 20]
user.github_access_token = auth.credentials.token
end
end
end
It's important to place self.from_omniauth(auth)
method definition right after devise
to avoid errors during authorization. devise
also should be on the top of the code.
9. Navigate to /users/sign_in
in your live app preview. Now you should have new nicely working button Sign in with GitHub.
It's time to make it look nice and add GitHub icon. If you've already generated views template for your Devise go to app/views/devise/shared/_links.html.erb
and replace this code:
<%- if devise_mapping.omniauthable? %>
<%- resource_class.omniauth_providers.each do |provider| %>
<%= button_to "Sign in with #{OmniAuth::Utils.camelize(provider)}", omniauth_authorize_path(resource_name, provider), data: { turbo: false } %><br />
<% end %>
<% end %>
With this:
<%- if devise_mapping.omniauthable? %>
<%- resource_class.omniauth_providers.each do |provider| %>
<div class="my-4" >
<%= button_to omniauth_authorize_path(resource_name, provider),
data: { turbo: false },
class: "btn btn-secondary" do %>
<i class="fa-brands fa-github pe-2"></i> Sign in with GitHub
<% end %>
<% end %>
</div>
<% end %>
If you don't have views for your Devise, generate it:
rails generate devise:views -b form_for
and then replace the code as described above.
For the icon I use Font Awesome so don't forget to connect it to your app. Go to your app/views/layouts/application.html.erb
and paste these lines of code into <head>
or use partials if you'd like.
Also don't forget to connect Bootstrap itself.
<!-- Connect Font Awesome -->
<script src="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/6.1.1/js/all.min.js"></script>
<!-- Connect Bootstrap CSS -->
<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/bootstrap@5.3.1/dist/css/bootstrap.min.css">
Feel free to change the color of the button using special Bootstrap classes. You can also adjust the space around the button by changing the class my-4
of <div>
. Learn more about Bootstrap's margins and paddings.
Also learn more about how to stylize the form itself using Bootstrap.
10. Since we store our secret keys securely in .env
they won't be commited because this file listed in .gitignore
. That's why we need to additionally define them for Render and GitHub itself in case you're using CI/CD pipelines. Let's start with Render. Navigate to Envinroment on Render.com and add your two keys there:
Go back to your app settings on GitHub and replace Homepage URL and Authorization callback URL with your deployed domain name.
11. If you're using CI/CD go to your repository on Github, then Settings > Security > Secrets and variables > Actions. Add New Repository Secrets.
In your app in .github/workflows/main.yml
add the following:
MY_GITHUB_ID: ${{ secrets.MY_GITHUB_ID }}
MY_GITHUB_SECRET: ${{ secrets.MY_GITHUB_SECRET }}
It should look like this:
Now commit your changes and create Pull Request. Your test should succeed.
If so merge your branch to main. It will trigger the deployment. It also should go well.
That's it! Enjoy your authorization with GitHub! 🥷
Top comments (0)