OAuth is Easy, Right?
OAuth can be easy to implement, but easy is in the eye of the beholder. This beholder will define it as leaning on a well-supported OAuth library and a simple user authentication flow.
We just wrapped up our first wave of GitHub integration with Skylight and while we did lean on a well-supported library, our customer authentication flow was not so simple.
We decided to use the GitHub strategy for OmniAuth instead of rolling our own GitHub OAuth implementation. Not only does this save us time, it allows us to leave the door open to other OmniAuth strategies (think Facebook or Google, etc.) and avoid maintaining our own solution.
GitHub allows users to configure OAuth applications. In our case, we created one for Skylight. When you sign into GitHub from Skylight, GitHub asks you if it's ok for Skylight to access your email and organization. You've probably encountered similar access confirmation screens when signing into other sites with Google or Facebook.
There are multiple ways to solve this problem, some of them highlighted by our awesome customers who heard we were working on this and emailed us with their suggestions. There were three ways we saw to tackle this: request parameters, GitHub's
state parameter (see guide) and session variables.
Using OmniAuth's GitHub strategy, we couldn't find a way to use the
state parameter. That doesn't mean it wasn't possible, it just wasn't obvious to us. OmniAuth already generates a value for this parameter and GitHub's guide states this parameter should be random and unguessable. We thought it best not to tinker with it.
It also wasn't obvious to us how to use request parameters with OmniAuth. Some of our customers explained how they used request parameters with their OmniAuth implementations and it's possible we may lean on their examples in the future.
We ended up storing certain bits of information in session, when applicable. This was very easy for us to implement and it allowed for a good amount of flexibility when handling the responses from GitHub.
To make things easy, we created specific routes for customers signing in, signing up, and connecting their existing accounts with GitHub.
# /config/routes.rb Application.routes.draw do get '/login/github' => 'sessions#github_login' get '/signup/github' => 'signup#github' get '/auth/github_connect' => 'sessions#github_connect' # For response from GitHub via OmniAuth get '/auth/:provider/callback' => 'sessions#github_create' end
This allowed us to use controller actions to set session variables and then redirect to
/auth/github which OmniAuth handles. All the GitHub authentication requests redirect to
/auth/github/callback so we can examine our session variables there. We ended up with a really simple solution allowing for very different ways to respond.
All the little things
As we've mentioned before, we believe it's all the little things that set Skylight apart. Small details can make a big impact. Most customers will enjoy a seamless experience. That said, we did want to account for the rare, not-so-happy path. Every interface has its odd states but most do little to no work on those edge cases. We put a lot of effort into uncovering those experiences and trying to make sense of them in our sign-in flow.
So... What is the happy path?
The ideal way for a customer to connect their existing account to GitHub is to first sign-in with their email and password, then head over to their Account Settings page to click the "Connect to GitHub" button, like so:
The customer will see their connected account information, and they can easily sign in with GitHub going forward. If for some reason the GitHub account you authenticate with is already connected to a different Skylight account, we'll let you know in our message bar at the top of the screen.
A common issue we noticed when looking at other apps that use OAuth sign-in is that it's really easy for a user to not actually remember if they signed up with an email/password combo, OAuth, or both. Speaking for myself, I usually forget as soon as I sign in 😛. We're aiming to mitigate that confusion by displaying that information right on the Account Settings page.
What happens if I have a Skylight account but I've never signed in with GitHub before?
We expect that many existing customers will click "Log In" first, and then click the "Sign In with GitHub" button.
In this case we will redirect the customer to an interstitial page with the email field pre-populated with their email address (via GitHub) and focus in on the password field, thus prompting them to sign in.
Once signed in, we connect their existing account to GitHub automatically, so they can go forth and sign in with GitHub to their heart's content!
What if I have a Skylight account and I click "Sign Up with GitHub"?
If the customer has already connected their existing Skylight account to GitHub, they will be signed right in to their account! A helpful welcome message will be displayed, just as a reminder in case the customer was not expecting to be signed in with this account (in cases where a co-worker may be signed in to GitHub on their computer, for example).
If the customer already has a Skylight account, but it's not yet connected to GitHub, and they've used the same email address for both, clicking "Sign Up with GitHub" will lead to the aforementioned interstitial page, but this time with a helpful error message. Just as before, all that's needed is to sign into their account on this page, and it will be connected to GitHub automatically!
At this point, you may be asking yourself, "so now I can log in with GitHub... so what?" We have a lot of great plans up our collective sleeves when it comes to GitHub - this is just the first round 😉🍻
Can't wait to push those shiny new GitHub sign-up buttons? Sign up for your 30-day Skylight free trial! Got a friend with some sweet GitHub repos? Refer your fellow VCS enthusiast and you both get $50 in credit.