Omniauth Lab

Objectives

  1. Identify "Strategies" in Omniauth
  2. Use the Developer Strategy with Omniauth
  3. Use Omniauth to provide OAuth authentication in a Rails server through a third party API

Introduction

In this lab, we'll be configuring our Rails application to request authentication from a third party. Typical third-party authenticators are Twitter, Facebook, and Google. We'll be configuring this application to use GitHub.

We won't be creating a full user sign-up flow. Depending on which third-party authenticator you use the data you receive will vary. As such, we're going to provide the scaffolding to ensure you're talking to the third-party authenticator and will set your expectations about what sort of data you might have available. At the end of this lab, you will have the ability to "extend" the application into creating user accounts (possibly leveraging what you know about Devise or has_secure_password).

To start, we'll implement a simple authentication scheme, provided by Omniauth, called "developer." The code in the "developer" authenticator is designed to help you make sure you have your application set up. Once "developer" is working as expected, we'll swap it for "github" and our app will look like something that you might see in the wild.

Identify "Strategies" in Omniauth

Omniauth is a flexible framework for third-party authentication. Omniauth supports a ton of authentication providers (full-list). Each of these pluggable providers is said to have a "strategy" that Omniauth can use. The word strategy here might seem strange, but it means something like "plug-in." It comes from the programming design pattern called "Strategy." As you grow in object-oriented skill, you might find yourself learning and even using the Strategy pattern. You can read more about the Strategy pattern (with sweet "Street Fighter" references). To get started, we need to include the "omniauth" gem and gems for any "strategies" we want to include. We've already provided them in the Gemfile.

Use the Developer Strategy with Omniauth

We'll start by following along with the instructions provided by Omniauth. Take a look at their "Getting Started" section and then come back.

These directions provide a file and a formula. In config/initializers, create a file called omniauth.rb and put in the following lines:

Rails.application.config.middleware.use OmniAuth::Builder do
  provider :developer unless Rails.env.production?
  # provider :twitter, ENV['TWITTER_KEY'], ENV['TWITTER_SECRET']
end

We don't have to know how Rails initializers work; we can just follow the Omniauth instructions. The name "initializer" suggests that they're used to set up Rails when we start it. We can learn more about initializers here.

Inside the block, we see that we're telling the Rails application to use a thing called OmniAuth::Builder which, inside of its block, adds providers. Providers are our authenticating third-parties. Each provider has a strategy. In the snippet above, we're saying "let's use the developer strategy."

We commented out the twitter strategy because we won't use it in this lab. Nevertheless, we're leaving it to show you that we can establish a decent hypothesis about what other providers' configurations will look like. GitHub's will probably be provider :github, ENV['Something GitHub-related'], ENV['Something else GitHub-related']. This winds up being exactly true.

But for the moment, our code has the active provider as :developer.

The documentation then says that we need to provide a route for the providers' strategies to "call back" to after the authenticating third-party decides whether the user has passed or failed authentication.

So let's add the following line to config/routes.rb. This is a bit different than what the documentation says, but it's a single line that's flexible enough to work for both the developer and github strategies.

match '/auth/:provider/callback', to: 'sessions#create', via: [:get, :post]

Once that's done, create a WelcomeController with an action called home. Make this route accessible by editing config/routes.rb and also make welcome#home be the root route for this Rails application.

WOW! That last paragraph integrated a lot of Rails knowledge. This is the level at which professional Rails developers communicate with each other!

Start your web server and visit the root route. Select Signing in with the developer strategy.

You'll be redirected to the "dummy" or "temporary" sign-up form for the developer strategy:

Developer strategy form

Fill in the name and the email address and submit the form...

Developer strategy form completed

Whoops!

Incomplete routing error

Looks like we need to finish implementing our SessionController. We've provided the logic for you inside of a method called xcreate. Rename this method to create and try again.

You should be redirected back to your Welcome#home route and you will see some diagnostic information on the screen.

We will put omniauth authentication data here (if present)

Welcome sgharms! We know who you are thanks to Omniauth!

You were authenticated by developer

The raw data returned from Omniauth were:
    {"provider"=>"developer", "uid"=>"test", "info"=>{"name"=>"Test User", "email"=>"test"}, "credentials"=>{}, "extra"=>{}}

Make sure you can step through the logic that Rails just performed:

  1. From the root route
  2. To the developer strategy's form which used the /auth/:provider/callback route to travel to...
  3. SessionsController#create which logged some diagnostic data and stored some authentication information in the session and then went back to the root route
  4. Which rendered an ERB file whose content changed because of what was in the session

We've proven we can log in via the developer strategy. We'll now ensure we can log in using GitHub's authentication.

Log in via GitHub OAuth Authentication

Getting things to work with GitHub, now that we have developer working, is much easier. There are many steps to undertake that have nothing to do with code. We'll be following the documentation in omniauth-github

  1. Update the OmniAuth::Builder to use a :github provider
  2. Provide it ENV variables from the dotenv gem
  3. That's it!

Credentials and DotEnv

Dotenv lets us store a list of "Secure keys" in a file called .env. The contents of this file are available as a Hash called ENV inside of our Rails application.

.env file snippet

Here, because we defined GITHUB_KEY in .env, we'll have its value available through ENV['GITHUB_KEY']

Because the .env file is full of secure keys, which are like passwords, we should NEVER EVER EVER ADD OR COMMIT TO THEM OUR GIT REPOSITORY. In this repository we've added .env to the .gitignore file so that git never sees the .env file.

If we ever commit and push these keys to GitHub or anywhere on the internet, WE MUST REVOKE THEM IMMEDIATELY. Because of the way Git is built, enterprising bad people can find commits with passwords easily.

So, we know we need to guard our keys and store them in .env...but how do we get them? For this we need to work with GitHub bureaucracy.

Getting our Keys

First, visit GitHub: https://github.com/settings/developers. When you're logged in, this site will let you click a button to create a "New OAuth App."

New OAuth App button

When we click it we'll be asked to fill in a form:

New OAuth Registry Form

The important part is to provide the callback path that you defined at the very beginning. Your app will hand off to GitHub, GitHub needs to know how to hand off back to your application (to, as it were, "call it back").

The form looks like this when filled in:

New OAuth Registry Form - Completed

Super! GitHub will then share our keys with us:

GitHub Credentials Display

Let's update our initializer (config/initializers/omniauth.rb) to look like:

provider :github, ENV['GITHUB_KEY'], ENV['GITHUB_SECRET']

You'll see that the ENV Hash's keys correspond to the contents of .env:

GITHUB_KEY=33...
GITHUB_SECRET=519...

With this in place, visit the root route and click the link that uses GitHub for authentication. You'll know you're on the right track when you see something like:

GitHub Authenticate Form

If you provide your GitHub credentials (including two-factor if it's enabled!), you'll be redirected back to our Session#create and then redirected, from there, back to the root route with GitHub information in the session.

Post GitHub Authentication

Congratulations! You just had GitHub handle user authentication for you!

Next Steps

Using third-party authentication is commonly used to help users create new accounts in applications. For examples of how this can work visit the Omniauth "Integration" document or consult their wiki.

Lab

If you follow along with this document, the lab should be passing at this point! Submit it and move on! If you'd like to create a new branch off of this repo (for further experimentation) feel free to do so!

View Omniauth Lab on Learn.co and start learning to code for free.