I’ve been messing around with some Twitch integrations in my free time. Twitch’s API is well defined and has some very good documentation around it. In this post, I’ll explain how I used an Ember Simple Auth custom authenticator to implement SSO (Single Sign-On) with Twitch.
1. Install Ember Simple Auth
In your Ember project, you can install Ember Simple Auth by running ember install ember-simple-auth
.
2. Create A Custom Authenticator
Ember Simple Auth comes with some canned authenticators for use with popular authentication protocols and libraries, such as Devise. The library also lets you define your own custom authenticators. We’ll define our own in this walkthrough.
A custom authenticator requires you to override two authentication functions: authenticate
and restore
. Our Twitch authenticator looks like this:
// client/app/authenticators/twitch.js
import Base from 'ember-simple-auth/authenticators/base';
import { run } from '@ember/runloop';
export default Base.extend({
store: Em.inject.service(),
session: Em.inject.service(),
authenticate(data) {
this.get('store').unloadAll('user-access-token');
return new Promise((resolve, reject) => {
return this.get('store').createRecord('user-access-token', data).then((user) => {
this.get('session').set('currentUser', user);
run(null, resolve, data);
}).catch((error) => run(null, reject, error));
});
},
restore(data) {
this.get('store').unloadAll('user-access-token');
return new Promise((resolve, reject) => {
return this.get('store').createRecord('user-access-token', data)
.then((user) => {
this.get('session').set('currentUser', user);
run(null, resolve, user);
})
.catch((error) => run(null, reject, error));
});
}
});
I’ve created an Ember Data model name user-access-token
to store and send the token to the server. That’ll allow us to make additional Twitch API requests on behalf of the user without exposing it to the Ember client. Whatever is returned in authenticate
will be stored in the session and used in the restore
function.
3. Authenticate With Twitch
Now that we have our authenticator implemented, we can make our request to Twitch. My app has a button that fires an action which redirects to Twitch for authentication.
There are a few required parameters for this request. You must provide your client ID, which you receive when you register your app within Twitch. The request must also include a redirect URI that exactly matches what you configure within Twitch. Lastly, it must include a scope. The scope tells Twitch what information you’ll be requesting about a user. Here’s what my component looks like:
export default Ember.Component.extend({
twitchLoginUrl: Ember.computed(function () {
return `https://api.twitch.tv/kraken/oauth2/authorize?response_type=token&client_id=${ENV.APP.TWITCH_CLIENT_ID}&scope=user_read+channel_read&redirect_uri=http://localhost:4200/oauth`;
}),
actions: {
authWithTwitch() {
window.open(this.get('twitchLoginUrl'), '_self');
}
}
});
If the user authenticates your application, Twitch will redirect to your configured endpoint with an access token. I’ve set up a route at /auth
to handle that redirect. That route will use the token to authenticate your user with the custom authenticator we created, and it will also set up a session for that user. I’ve provided mine below for reference.
import Ember from 'ember';
export default Ember.Route.extend({
session: Ember.inject.service(),
model(params, transition) {
let tokenHash = document.location.hash.substr(1);
let tokenValue = tokenHash.substr(tokenHash.indexOf('access_token=')).split('&')[0].split('=')[1];
this.get('session')
.authenticate('authenticator:twitch', {token: tokenValue})
.then(() => {
this.transitionTo('dashboard');
})
.catch(function(error) { console.log("error", error);});
}
});
Your application has now authenticated a user through Twitch. Depending on the scopes your application requested, you can now make additional API requests to gather more data.
Would the route be auth, or oauth, based on:
return `https://api.twitch.tv/kraken/oauth2/authorize?response_type=token&client_id=${ENV.APP.TWITCH_CLIENT_ID}&scope=user_read+channel_read&redirect_uri=http://localhost:4200/oauth`;