Add Omniauth GitHub to Your Rails App on Top of Devise
Last update: 16 July 2018
As I’ve moved into the last three weeks of @lewagon, my teammates and I have been working on marketplace apps before getting to our final projects.
The need to authorize people to sign-up with GitHub quickly arise. Here’s a step-by-step tutorial on how to do it when you already use Devise to handle authentification.
Basic set up
Before working on your app, you need to set some things up.
Create a application on Git Hub
First, we need to create a OAuth app on GitHub. Go to your profile, then developper settings
and click New OAuth App
.
Give your application a name, a URL and a callback URL. What if you want to work with localhost? Glad you asked.
For your homage URL: http://http://localhost:your_port
will work perfectly
For the callback URL, you can’t use http://http://localhost:your_port
because GitHub needs you to specify an address that can be publicly access. So, what do we do?
ngrok to the rescue
ngrok exposes your local web server through a public URL. So we need to install ngrok and have it listening to our local server. We’ll then be able to get a public URL and give it to GitHub.
First, run in your terminal:
Then run:
You’ll get:
And there you have your callback URL: http://3aa8f0f7.ngrok.io -> localhost:3000
.
Do not forget to append your callback URL with /users/auth/github/callback
.
Your development callback URL should look like this:
http://3aa8f0f7.ngrok.io/users/auth/github/callback
We’ll need to change these two URLs once we move into production. ⚠️ Be careful to use the same protocol in your app URL and callback URL. Using http
in one and https
in another with result in a URL mismatch.
Save your API keys in your Rails app
We don’t want our API keys being pushed to GitHub. So I’ll use the figaro gem to store these in a secure file.
Figaro creates a config/application.yml to put all your API keys and adds this file in .gitignore.
Copy/paste your secret keys in config/application.yml
Don’t forget to tell devise to use these keys in config/initializers/devise.rb.
Configure Omniauth GithHub with Devise
Since we use Devise to handle authentification, we don’t want to write config in config/initializers/omniauth.rb.
Let’s get down to it!
The first step is to had the Omniauth gem to your app. Go to your Gemfile
:
Then run:
Next step is to add the provider
and uid
columns to our User model. Remember we already declared the provider in our config/initializers/devise.rb.
We go to user.rb
and make our user omniauthable.
With devise_for :users
already in place, Devise will create two URL methods:
user_omniauth_authorize_path(provider)
user_omniauth_callback_path(provider)
_
Add it to your view
Paste the following code to get a simple link to test it out:
⚠️ The symbol passed to the user_omniauth_authorize_path
method should match the symbol of the provider passed to Devise’s config block.
Now, when clicking on Sign up with GitHub
, people will be redirected to GitHub to give their credentials. But as for now, nothing happens when GitHub sends back the user’s data.
Add the callback to your app
Let’s go back to our config/routes.rb
to tell Devise in which controller we’ll implement our callbacks:
Now we just add the file app/controllers/users/omniauth_callbacks_controller.rb
:
The callback should have the same name as the provider we passed in Devise’s config block.
Then, from the controller, we move to our user model. Here is the code from Devise documentation:
After changing the code above to suit my primary needs, I ran into several problems:
- I was using Carrierwave to upload picture on Cloudinary, so I needed to add the proper logic to the method.
- If a user was already persisted in my DB and was trying to sign-in with GitHub, he was redirect to sign-in without logging in.
So, here’s my own version of the Class method based on my schema and needs:
What caused the second problem was that the model had two validation strategies conflicting with one another:
- Devise
- and Rails native
validates
method.
My user model had a validates :password, presence: true
that was raising an error and preventing user from logging in. This useless line of code was caused by a lack of communication within our team. Talking more with each other would have saved us a lot of debugging ☝️.
Push into production
After testing and merging my branch on GitHub we pushed it to Heroku. It’s important at that point to go back to your GitHub app page and update the app URL and the callback URL with your domain name.
Your app URLs should now look like these:
Homepage URL: http://your_app_url.your_domain
Callback URL: http://your_app_url.your_domain/users/auth/github/callback
Also, don’t forget to give Heroku your API keys. Otherwise your production environnement will not know how to interpret config.omniauth :github, ENV['GITHUB_ID'], ENV['GITHUB_SECRET'], scope: 'user,public_repo’
in your config/initializers/devise.rb (and your users will get a magnificent 404).
Don’t forget to run:
And here it is, now people can sign-up and sign-in to your app using their GitHub credentials. 🙌