"Who are you?" may be the line sung by Roger Daltrey of The Who in their 1978 hit Who Are You, but it is also the fundamental question that Authentication answers.
Authentication is the process of determining whether or not a user is who they claim to be. You are likely familiar with the basic process. You sign up on a website with an email and password. The next time you log in you will be prompted for your email and password. If both your email and password are correct, the application verifies or authenticates your identity.
But what if we've already gone through this process on another site? Wouldn't it be nice if we could somehow communicate with that site's authentication system and use it to authenticate the users on our site? This is precisely what OmniAuth allows us to do, specifically through the use of community-built strategies, or code that allows one to authenticate to a given provider, e.g. Facebook or GitHub. You know those "Login with Facebook" buttons? Yep, that's what we're talking about here.
In this post, I will go over the steps I took to authenticate to GitHub in a Rails development environment using the omniauth-github gem, "the official OmniAuth strategy for authenticating to GitHub", along with Devise, and the figaro gem.
For some OAuth providers, you will need to install something like ngrok, a nifty tool that exposes your local WebHost to the internet.
This guide will assume you already have Devise authentication setup for your app. See the link above for installation instructions.
We will go over the following steps in more detail below.
- Installing the figaro gem to securely store our OAuth Client ID and Client Secret.
- Registering a new OAuth app with GitHub to use the GitHub API.
- Configuring Omniauth GitHub and Devise.
- (Optional) Installing ngrok to expose localhost to the internet and obtain a functional callback URL.
Note: setting up an ngrok tunnel is only necessary if your OAuth provider does not allow local callback URLs.
GitHub does allow localhost callback URLs, so I will include this step as a courtesy if your OAuth provider disallows localhost callback URLs.
The first step is fairly straightforward. We need a method for securely storing the keys we will obtain in Step 2. Figaro does this by creating a
config/application.yml file and adding it to
.gitignore. This way your secret key will never be pushed to GitHub and will stay on your local machine.
To install Figaro:
- Add it your Gemfile:
- Install figaro:
bundle exec figaro install
See the gem documentation for more details. We will return to the
config/application.yml file generated by
bundle exec figaro install after we register a new OAuth app on GitHub (Step 2).
To authenticate to GitHub, we must tell GitHub who we are and that we will be requesting information from its API. To do this, we must register our application as a new OAuth app. Navigate to GitHub. Login and under your profile picture, click on Settings. Scroll down a bit and click on Developer Settings. Click on OAuth Apps, and finally "New OAuth App".
- Name your application
- Under "Homepage URL", enter
http://localhost:3000as this is the homepage of your application in development.
- For "Authorization callback URL", enter
- Click "Register Application".
- Take note of your client id and client secret.
In your Rails application, navigate to
config/application.yml and save your client id and secret:
development: GITHUB_ID: < client id > GITHUB_SECRET: < client secret >
Follow the directions in the Devise Wiki.
- The examples use omniauth-facebook, but you can essentially replace any occurrence of 'facebook' with 'github', or 'twitter', etc.
- scope entails the permissions you request of the authenticated user. "Access to email, profile info, etc."
scope: 'user,public_repo'below grants access to basic profile information and all public repo information. GitHub provides these scopes in their docs
- Don't forget to add a "Sign in with GitHub" link.
- for the
config/initializers/devise.rbpart, your entry is accessing the environment variables set by Figaro:
config.omniauth :github, ENV['GITHUB_ID'], ENV['GITHUB_SECRET'], scope: 'user,public_repo'
- ngrok is a tool that exposes a local web server to the internet. The colloquial term for this is a tunnel.
- ngrok allows us to use a callback URL in development when an OAuth provider does not allow local callback URLs.
- The callback URL is essentially where a user is redirected after authenticating to a third party service.
- Some OAuth providers require that this URL be public, thus the need for a tool like ngrok.
- After an application, located at
localhost:3000sends a request for authentication to the OAuth provider's API, the OAuth provider "calls back" the publicly exposed WebHost's URL and the application now has an authenticated user.
- For GitHub, we did not need to publicly expose our localhost server. We simply used
http://localhost:3000/users/auth/github/callbackin Step 2 above.
To install ngrok follow the instructions:
snap install ngrok(Ubuntu) or
brew install ngrok/ngrok/ngrok(Mac)
- Sign up for an account to get your authtoken.
- From your home directory:
ngrok authtoken <token>
- Start a tunnel. For a Rails app, use port 3000.
ngrok http 3000
The final command,
ngrok http 3000, will bring up the ngrok UI:
- Note the forwarding URL.
- Return to your application's settings and add
/users/auth/< insert_provider_name >/callbackto the end of the forwarding URL.
- Navigate to localhost:3000, or, if you're using ngrok, your ngrok forwarding URL (Ctrl+click from terminal), and click the "Sign in with GitHub" link you made earlier.
- You should now be able to authenticate a GitHub user in your application in Development. Try it out with your own GitHub account!
- If you're using ngrok for your Authorization callback URL, it may be necessary to add your ngrok domain to your list of allowed hosts in
config.hosts << "0e30-73-119-170-171.ngrok.io"
- This will need to be changed if you close the terminal session that holds your ngrok session.
- Return to Step 2:
- On GitHub application page, update your "Homepage URL" to
< your app's production domain name >
- Update "Authorization callback URL" to
< your app's production domain name >/users/auth/github/callback.
- On GitHub application page, update your "Homepage URL" to
- Update your
config/application.ymlfile to include a production environment.
- Set Heroku config variables so Heroku can access your application keys
heroku config:set GITHUB_ID=github_id_key_here
heroku config:set GITHUB_SECRET=github_secret_key_here
- Deploy to Heroku
I was quite happy when I saw the "Successfully authenticated from Github account." flash message. Getting this to work was an exercise in patience and reading documentation slowly and carefully. Authentication is a deep topic and I feel I have only scratched the surface. I hope this post was a helpful guide on how to setup OmniAuth in a development environment. Before we walk, we must crawl. Before we deploy to production, we must struggle in development.