How I Have Created an Eventbrite Clone with Ruby on Rails: Part V
How to add OAuth to an existing app with devise
Part I Part II Part III Part IV Part VI Part VII
This is part 5 of my tutorial on how to complete a project of cloning Eventbrite with Ruby on Rails from scratch (full project description here), which is a part of the Ruby on Rails Full Stack Path (link here) from the Odin Project. I have implemented OAuth logins through Github and Google. This part is not in the requirements from theOdinProject, but I have done it as a way of learning and improving my technical skills.
Step 1. Adding OAuth
If you are not familiar with OAuth, it is basically an authorization framework that allows you to log into a web application through your existing accounts with websites such as Facebok, Github, Google, etc. In other words, you can configure you web app to use OAuth to log in to your website from other common websites that many people have, to make it easier for them to sign up for your website. For more details about OAuth, please check here.
We’ll add OAuth logins with Github and Google in this tutorial.
First, we need to register with Github and Google.
Step 1.1 Register with Github
To register with Github, open your https://github.com/settings/developers page, and then click Developer settings in the left menu, as shown in Fig 1.
Then you’ll see https://github.com/settings/apps in your browser. In the left menu, click OAuth Apps, as in Fig 2.
Then click the New OAuth App button on the right-hand side of the OAuth Apps page.
Then a form in Fig 4 will be displayed. Enter whatever you like for Application name, http://localhost:3000 for Homepage URL, and most importantly, enter http://localhost:3000/users/auth/github/callback for Authorization callback URL (we’ll change the callback URL in the part where we’ll talk about implementing a deployment in Heroku).
Then on the OAuth Apps page, click your app name and look for the Client ID and Client Secret. Save your client ID somewhere. Then click the “Generate a new client secret” button on the right-hand side. Copy and paste the generated client secret somewhere (we will only see it once). If you can’t find any location of what I have talked about in this paragraph, please refer to Fig 5 and Fig 6.
Step 1.2 Register with Google
Assume you are logged in to your Google account, open https://console.cloud.google.com/, and then create a new project by clicking, like in Fig 7.
Then click More Products, next API & Services, and then Credentials (Fig 8).
Then on the Credentials page, click the button “+ CREATE CREDENTIALS” and then click OAuth client ID in the dropdown menu, as shown in Fig 9.
Click Web application in the Application type, like in Fig 10.
After you select Web application, a new form will show up. Enter the following URI in for Authorized redirect URIs and then click CREATE:
http://localhost:3000/users/auth/google_oauth2/callback
Then a page titled OAuth client created will pop up, as in Fig 12. Save your Google client ID and client secret somewhere.
Step 2. Configure OAuth in Your App
Step 2.1 Add gems
Now let’s set up OAuth with devise. First we’ll add the gems needed for OAuth in our Gemfile like shown in Fig 13. Then run bundle install to install them.
Step 2.2 Add two fields for the User model
Then we need to add two fields to our User model, a provider string (here our providers would be Github and Google) and a UID string. Run the code below and you should see the result printed in Fig 14.
rails g migration AddOmniauthToUsers provider:string uid:string
rails db:migrate
Step 2.3 Add code in the User model
Then add the following code to the User model in /app/models/user.rb for devise after your existing code for devise:
devise :database_authenticable, :registerable, :recoverable, :rememberable, :validatable,
# add the following code
:omniauthable, omniauth_providers: %i[github google_oauth2]
Now if you run rails routes, you’ll see that four routes for OAuth were already added by devise. Check if new routes in Fig 16 were added. The beauty of using devise is that a lot of features related to authentication were already implemented, and you just need to do some configuration to use whatever features you need.
Create a class method called from_omniauth(auth) in the User model. We’ll use this method in our callback function for a callback controller which we’ll create next.
def self.from_omniauth(auth)where(provider: auth.provider, uid: auth.uid).first_or_create do |user| user.email = auth.info.email user.password = Devise.friendly_token[0,20] user.username = auth.info.nameend
Step 2.4 Create omniauth_callbacks_controller
In your terminal, enter mkdir app/controllers/users, then enter touch app/controllers/users/omniauth_callbacks_controller.rb. Then add the code shown in Fig 17.
mkdir app/controllers/users
touch app/controllers/users/omniauth_callbacks_controller.rb
Step 2.5 Add buttons in the view to enable OAuth logins
Next, we’ll add two buttons for the OAuth in /app/views/layouts/application.html.erb in the navbar. Please note that we are using button_to (instead of link_to, due to the reasons mentioned here), and also that the two paths used here are the two authorization paths we saw in Fig 16. The code is in Fig 18. Also pay attention to put the two buttons in the else block, since we will only need to log in when we are not logged in.
Step 2.6 Safely Storing Your Secrets
To safely storing your secrets (yes you should very carefully store your secrets in your environment), we need to use a gem called figaro which was already in Fig 13.
Since the gem figaro was already added and installed, just run bundle exec figaro install in your terminal. You can see that config/application.yml is generated and it’s automatically appended to .gitignore. We’ll be storing our secrets in config/application.yml. By doing this, your configuration in application.yml will be automatically ignored when you do a git push.
Now open config/application.yml and store the values of your Github client ID, Github client secret, Google client ID, Google client secret as shown in Fig 20 (Please be noted that I called google_oauth2_client_id for the Google client ID and google_oauth2_client_secret for the Google client secret here):
To verify if the secrets are stored in your ENV variables, start your rails console by running rails c and then enter ENV, you should be able to see your secrets at the end, like in Fig 21:
To make use of OAuth for devise, we should next configure in /config/initializers/devise.rb. Add the code shown in Fig 22 after # ==> OmniAuth in your /config/initializers/devise.rb.
Add the routing for the OmniauthCallbacksController in /config/routes.rb, shown in Fig 23. This new route is telling devise that we are using the OmniauthCallbacksController which is in /app/controllers/users for omniauth_callbacks and then devise will take care of the rest.
Start your rails server again and open your browser. Log out if you are logged in, and if everything is working, you should see in your navbar, two new links were added, like in Fig 24.
Now click “Google Login” to verify if everything is working for now. If you happen to see a 400 error: redirect_uri_mismatch, like in Fig 25, it means that the URI you have configured in Fig 11 was not correct. Please double-check.
If everything is alright, you should see a window like in Fig 26.
After you select the Google account you’d like to log in with, you will be directed back into your localhost. You should see your full name for that Google account in the middle of navbar, with a flash message above the navbar saying that you have successfully authenticated from the Google account, as shown in Fig 27.
To test our Github login, click the Logout button in the navbar, and then click Github Login. If everything works well, you should be redirected to your localhost and see your navbar as shown in Fig 28. However, if after you are redirected to your localhost, you are still not logged in, and you see an error message (or no error message displayed) saying that Email has already been taken and be redirected to the User Sign Up page, please try deleting the user account from your rails console and then try again.
With that, we have reached the end of this part of the tutorial. In the next part, we’ll go over how to create REST APIs for existing functions.
A complete list of the code changes is listed here.
Thank you so much for reading.