Social Sign In + Ember

Jordan Morano
Icarus’ Wings
Published in
5 min readFeb 25, 2015

The Goal

Social sign-in appears to be a simple feature on the outside that is quite complex once you dive below the surface. I knew going into it that it was an ambitious goal to achieve three social sign-ins on an Ember app.

Let’s get to it then- in the most simple and concise way possible. This assumes that you use Ember Simple Auth to handle the client-side authentication, Ember CLI as the app framework, and authorization headers with tokens to manage the session and send requests to the server.

The goal is to introduce an additional sign up flow other than password grant that looks something like this:

  1. User authenticates using a third party provider, like Facebook.
  2. We take that authorization code and send it to our rails server.
  3. We get the access token and user info from the provider’s api.
  4. We compare that user info with our user table and match that user to either a pre-existing user via email or create a new one.
  5. We save the identity linking all of this information (provider, UID, access token, and user).
  6. Finally, we create and send back our own application’s OAuth token to authenticate the user’s session.

Client-side authentication with a provider

The first stop is to familiarize ourselves with the Torii plugin and install it on our app. This handles all of the heavy-lifting that authorizes the user with the provider.

We want to add the configuration settings to our environment.js file for all of the providers with which we want to authenticate. It will look something like this:

Build a Torii Provider

The next step is to build our provider. If you aren’t already familiar, I would encourage you to take a look at Torii’s readme for an in-depth explanation. For the providers that use OAuth2, like Facebook and Google+, Torii comes with provider definitions that connect and authenticate with the third party.

Since we want to authenticate the user in our application after getting the third party authorization, this out-of-the-box functionality isn’t yet complete. To complete this we extend the default open method through a creative use of this._super():

It is important to note that at this point we only get the authorization code back from the provider. We make a POST request to our server to fetch the access token and user information.

We then want to include this logic in our provider definition. Torii looks for its providers to be defined in the app/torii-providers directory. By using the same provider name, like facebook-oauth2, we can reopen, access and override the built-in providers. This replaces Torii’s facebook-oauth2 with our own facebook-oauth2 and custom open functionality.

Build a Custom Authenticator

Now we want to define our own custom authenticator. We can do this in the app/authenticators folder or wherever (location doesn’t matter since we will import it explicitly later).

Since we are using OAuth2 for our normal password sign-in flow, it is important to extend our authenticator from OAuth2.

We register it on the container and make sure that its torii property is defined; this lets us use the torii functionality.

Use the Custom Authenticator

Registering the authenticator on the app’s container, allows us to simply use it when we want to:

Here we have an action that can get mixed into our sign-in and sign-up controllers, called with the provider name passed in as an argument. This allows us to handle multiple provider sign-in buttons on the same page.

That’s it from the client-side! With the above code, we’ve accomplished fetching the authorization code from Facebook and passing it back to our rails server. Now we need to verify that code and return back an access token for our application if successful.

Rails-side verification and access token

We’ve now sent a POST request to our server with these three params: authorization_code, provider, and grant_type.

Create a Custom Endpoint

We send this information to an action on the OAuth controller.

Here we pass our provider and code params to a class method on an Identity model. We then persist that information and upon success we create a new OAuth token and render it back to the UI.

The Identity model and table stores the provider information (access token, user id, provider name), as well as the user association. The key purpose of this model is to take the authorization code and provider and locate or create a new identity for the user. Let’s take a closer look.

Identity Model

This model is the link between our application and the provider for a user. With an authorization code and provider, it should be able to check that the code is correct and sync up the user. We use a single class method to handle this:

Looking at this closer, we use a PORO (Plain Old Ruby Object) service, RequestToken, to handle the API requests to the provider. RequestToken.request returns an instantiated object that contains user_data and the access_token. We use the user id from the provider (the UID) to initialize or find an identity model.

If we add email, first name and last name as attr_accessors on the Identity model, we can find or create the user association in a callback- I found this useful and self-contained.

So what is going on in the RequestToken service? Let’s take a look.

RequestToken — where provider api logic lives

It is here that that we handle all of the API calls to the provider. We can store the api urls in a hash constant and dynamically reference the correct one based on the provider.

There are two API calls that we make: one to fetch the access token and another for the user information. We write two separate methods for this:

We use HTTParty to handle the requests. It’s nice that the OAuth2 specs make the requests conventional across different providers. The above works for Facebook, Google+, and LinkedIn.

We need to also make sure to define methods to point to the correct api key and api secret, based on the provider.

Wrap up

That’s pretty much it! Hope you enjoyed the ride. I was able to add social sign in for LinkedIn, Facebook, and Google+ using the above approach. I plan to go over Twitter authentication in a separate post, which uses slightly different logic and OAuth1.

Thanks for reading! In case you are curious, we have more articles and info on software development, who we are at IcarusWorks, and life on our publication page and website.

--

--