Series: User Auth

Github OAuth2 Authentication with Torii

Published on Oct 05, 2016

Usernames? Passwords? So much to remember. Why not let your users login with 1 click using Github? (Or Facebook, or Twitter, or LinkedIn, or Google, or....)

This extra-long EmberScreencasts walks through the implementation of 1-click Github authentication used at EmberSchool.com. It's big, it's complex, but we go through it step by understandable step, and it will end up being great for your users.


Links

Code

$ ember install torii
//config/environment.js
/* jshint node: true */

module.exports = function(environment) {
  var ENV = {
    torii: {
      providers: {
        'github-oauth2': {
          apiKey: 'YourClientId'
        }
      }
    },
  }
}
//services/session.js
import Ember from 'ember';
import ENV from "ember-school-client/config/environment";

export default Ember.Service.extend({
  currentUser: null,
  torii: Ember.inject.service(),
  ajax: Ember.inject.service(),
  store: Ember.inject.service(),
  login(){
    return this.get('torii').open('github').then(data => {
      Cookies.set('authenticationToken', data.accessToken)
      return this.get('ajax').request(`https://api.github.com/user`)
    }).then(user => {
      return Ember.$.ajax({
        method: "POST",
        url: `${ENV.host}/users`,
        data: {
          login: user.login,
          email: user.email,
          name: user.name,
          authentication_token: Cookies.get('authenticationToken'),
          avatar_url: user.avatar_url,
          github_id: user.id
        }
      })
    }).then( user =>{
      Cookies.set('userId', user.user_id)
      this.initializeFromCookie()
    });
  },
  logout(){
    this.set("currentUser", null);
    Cookies.remove('userId');
    Cookies.remove('authenticationToken')
  },
  init(){
    this._super(...arguments);
    this.initializeFromCookie();
  },
  initializeFromCookie(){
    var userId = Cookies.get('userId');
    if(!!userId){
      let user = this.get('store').findRecord('user', userId);
      this.set('currentUser', user);
    }
  },
  isLoggedIn: Ember.computed.bool('currentUser')
});
//torii-providers/github.js
import Ember from 'ember';
import GitHubOauth2Provider from 'torii/providers/github-oauth2';
import ENV from "ember-school-client/config/environment";

export default GitHubOauth2Provider.extend({
  ajax: Ember.inject.service(),
  fetch(data) {
    return data;
  },
  open() {
    return this._super().then((toriiData) => {
      const authCode = toriiData.authorizationCode;
      const serverUrl =  `${ENV.host}/github_auth?code=${authCode}`;

      return this.get('ajax').request(serverUrl)
        .then((data) => {
          toriiData.accessToken = data.token;
          return toriiData;
        });
    });
  }
});
class SessionsController < ApplicationController
  def github
    client_id = ENV['GITHUB_CLIENT_ID']
    client_secret = ENV['GITHUB_CLIENT_SECRET']
    code = params[:code]
    @result = HTTParty.post("https://github.com/login/oauth/access_token?client_id=#{client_id}&client_secret=#{client_secret}&code=#{code}")
    @access_token = @result.parsed_response.split('&')[0].split('=')[1]
    render json: {token: @access_token}
  end
end

Transcript

Hey everyone. If you’ve been keeping up, you probably know that I’ve launched EmberSchool. And I think it’s really cool and you should go check it out, but the reason I’m bringing it up is because I want to show one of the cool technical features of EmberSchool, that is you can log in with GitHub. So after you’ve approved GitHub, you can do a one click and boom, you’re logged in. And I do that using torii. Torii is a tool that makes OAuth2 applications easier, so that’s connecting to GitHub, to Twitter, to Google, Facebook. Here’s a list of some of the built-in providers to torii. So OAuth2 is a pretty complex subject. I mean if you go to the GitHub docs on it, they are not exactly easy. It’s not super obvious what exactly you need to do. So what we’ll do is we’ll go through and we’ll do it step by step. And I’m not guaranteeing that the way I’m going to show you is the best way, but it’s a way that works, and it’s specifically about GitHub, but it should help you do all of these other providers as well.

So first, we install the addon. Now we’re installing version 0.8, which as of this recording is the most recent version. Then once it’s installed, we need to set up the environment. So we go to environment.js and we have a torii hash and we set up our providers. We’re going to be using github-oauth2, and then we’re providing an apiKey. And don’t freak out that I have this in plain text. This is the client id, not the client secret. So how you’re going to get the client id is... so you’ll go to your ‘Settings’ in GitHub, and then you’ll scroll down to ‘OAuth applications’ under ‘Developer settings’, and you might have to ‘Register a new application’. But I already have mine set up, so if I clicked on it it would give me both this client id and the client secret. I’m not going to click on it because the client secret is actually secret, but the client id you’re going to be sending that with your app anyway, so no reason to hide it.

Now to understand the rest of this video, you’ll need to be familiar with session services and cookies as well, so it’ll be helpful if you watched this older sequence. You could also have watched the sequence covering similar topics in EmberSchool. So we have our session service, and there are lots of places that were calling the session service and then kicking it up there to the login method that we have there. So here we’ve defined login, and we’re doing quite a bit. We’re going to focus at the start on just this line. So we’re calling to get torii, and that is of course injected as a service. Then we’re calling the .open method. So that’s how you call all of the torii things. So you call .open, and here it’s a github. You could put Facebook or any of the other providers.

And we’re not here using the default GitHub provider. We’re using one that I’ve customized. So what I’ve done is I’ve imported the GitHubOauth2Provider from torii/providers/github-oauth2, and I’ve extended it, and I’ve overridden the open method, but I start off by calling super. So this isn’t necessarily the recommended way to do torii, but it worked for me because then I could see all the moving parts and make sure that I got the right ones where they needed to be. If you do some of the defaults, there are lots of moving parts and it can be hard to tell what you need to do when. And if you know it really well already, then it can work out really great and be really easy. But if you don’t then it can be super difficult, just because it is sort of a black box. So what we’re going to do is we’re going to put a debugger statement here and see what kind of data we get from calling super.

So our first attempt to testing this, hit ‘Authorize’, and of course we will authorize the application, but it just skips through. And this is super weird, I don’t know why it’s doing this, but if we put in a second debugger, then now it catches it on the second debugger. So please tell me in the comments if you know why it’s doing that. Anyway, so we’ve got the toriiData and it’s giving us the authorizationCode and the provider, the redirectUri. The important thing is the authorizationCode, because that’s what we’re going to use next.

So we get that authorizationCode and we use it to create the serverUrl. So it’s basically our host name, here www.emberscreencasts.com /github_auth and then code= this authCode. Then we’re going to make an ajax request there and get back some data. So we’ll take a look at the server. So on the server, now we have both the client_id which our client had, and the client_secret which we did not put on ember because then people could’ve seen it and it’s a secret. And we’re also getting the code, and then we can send a post to github to login with oauth and we’re sending the client_id, the client_secret, and the code. And those are all done as query params to this route.

Alright, so we get the result and then we get the access_token from here... yeah, there may be better ways, but anyways this does work, and we send back the token with json. So we get the data hash back and we pull the accessToken from it and we put that on the toriiData. So the toriiData now has the authorizationCode and the accessToken. And then we send it back to our session service. And that’s what’s in here, in the data route. And we’re going to set the accessToken as our authenticationToken, and that’s what we’re going to be using to talk to the server from now on. Now we’re going to pull a lot of user data from GitHub, so we’ll make an ('ajax').request to the api.github.com/user link. And you may be wondering, how does it know which user?

So this is the XHR request. Here is the url. And not only does it have the oauth client id, but in the request headers it also has our authentication token. And then you can see in the response preview that it gets all this information or some of its urls where you can get certain information about my id, about my github user, and that user is what’s returned here from the promise. So that’s what’s passed in to the next thenable block, and from there on we go and we create a user on the server, and we’re using all the various fields as well as the authentication from the cookies. And from then on, it’s just the same basic stuff that we covered in this series.

So that’s how we get this cool feature. Very easy login. Let’s go ahead and review. So first, you install torii. Then, you set up your developer application. You might have to register a new one at the place where you’re wanting to connect to, in our case, github. Then you... in your environment.js, you set it up. Here the apiKey is called client_id. Then in your session service, when you’re calling... we call it login, that’s a pretty good one, then you hit torii, and you call .open for the service that you want to use. Here we’re using github. And then, we’ve also customized it. So the customization is in the torii-providers folder, in the github file, and the main thing we’ve done is we’ve extended the GitHubOauth2Provider which we import from this path, and then we’ve also extended the open method. So we call super to get a bunch of data from the default torii call, and then we remove these two debuggers, for some reason we needed two debuggers to stop it instead of one. Anyway, we grab the authorizationCode and we send that to our server.

So what we’ve done so far is we’ve talked to github and they send us back an authorization code on our user’s client, on our user’s ember app. And then that ember app is sending it to our Rails server, right here. And that Rails server has another secret that it’ll use to send to github again, and it’ll use the client_id, the client_secret, and the code that our ember app has gotten from github. So what’s happened so far is you send it from the ember app to github, and github sends you back a code, and then you send that code to your server, in this case Ruby on Rails, and your server has extra information, as well as that code now, so it’ll call to github again and it’ll get your access_token. And your access_token is where so much of the magic happens. Alright, so you get your accessToken back, and we send it back to the session service, and we set it as the authenticationToken in our Cookies. And now that it’s set, we can send it with the request. So we send a request to github in order to get information about the user.

So to go over all this completely, we go from ember to github that sends you back the authorizationCode. You send the code to your server. The server then combines the code with the client_id and client_ secret in order to talk to github to get the accessToken. Get that accessToken and then you use that accessToken in order to request information about that user from github. Now you may be thinking, wow, that sure was a lot just to get this simple feature, and you’d be right, but that is how it’s set up and I think it’s worth it to be able to have something this awesome.

User Auth

Subscribe to our mailing list