How I Have Created an Eventbrite Clone with Ruby on Rails: Part V

Brenda Zhang
8 min readJan 14, 2022

How to add OAuth to an existing app with devise

Photo by Ferenc Almasi on Unsplash

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.

Fig 1. Click Developer settings

Then you’ll see https://github.com/settings/apps in your browser. In the left menu, click OAuth Apps, as in Fig 2.

Fig 2. Click OAuth Apps in Developer Settings

Then click the New OAuth App button on the right-hand side of the OAuth Apps page.

Fig 3. Click the New OAuth Apps button

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).

Fig 4. A form to enter for registering your app

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.

Fig 5. Look for Client ID and Client secrets on your app’s page in OAuth Apps
Fig 6. Your client secret will be displayed in highlighted part

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.

Fig 7. Select an existing project or create a new project

Then click More Products, next API & Services, and then Credentials (Fig 8).

Fig 8. Click APIs & Services, then Credentials

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.

Fig 9. Click OAuth Client ID in the dropdown menu of + CREATE CREDENTIALS button

Click Web application in the Application type, like in Fig 10.

Fig 10. Click Web application in Application Type

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
Fig 11. Enter this URI for Authorized redirect URIs and click CREATE button

Then a page titled OAuth client created will pop up, as in Fig 12. Save your Google client ID and client secret somewhere.

Fig 12. OAuth client created window

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.

Fig 13. Add the other three gems for OAuth in Gemfile

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
Fig 14. Add two fields to the User model to use OAuth

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]
Fig 15. Add the code for OAuth in your User model

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.

Fig 16. Four routes for OAuth were added by devise

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
Fig 17. Code in OmniauthCallbacksController

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.

Fig 18. Add two buttons in /app/views/layouts/application.html.erb

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.

Fig 19. Run bundle exec figaro install in the terminal

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):

Fig 20. Add all your secrets to config/application.yml

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:

Fig 21. Check your secrets in rails console

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.

Fig 22. Configure OAuth for devise in /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.

Fig 23. Add the code in the highlighted part in /config/routes.rb

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.

Fig 24. Two buttons for OAuth are added in navbar

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.

Fig 25. redirect_uri_mismatvh error

If everything is alright, you should see a window like in Fig 26.

Fig 26. The window from Google displayed when everything is working

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.

Fig 27. Your navbar and the flash message after successful login with your Google account

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.

Fig 28. Your navbar with the flash message after successful authorization with your Github account

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.

--

--

Brenda Zhang

A backend developer, mainly using Ruby on Rails for the time being, a lifetime learner.