amkirwan / ember-oauth2

JavaScript library for using OAuth 2.0 Implicit Grant flow (Client-Side Flow) with Ember.js
MIT License
133 stars 22 forks source link

Ember CLI support #20

Open AlbertGazizov opened 9 years ago

AlbertGazizov commented 9 years ago

Does anybody use this library with Ember CLI app? What should be added to the RedirectURI template? The README uses global App variable approach which doesn't work for CLI applications.

amkirwan commented 9 years ago

Yes you can absolutely use this in an EmberCLI app. I'm currently using it in several Ember 2.0 apps.

The README show how to setup ember-oauth2 using both a CLI module based app and a using a global. For EmberCLI you need to setup your configuration in config/environment.js using the EmberENV global so you can access the configuration.

Then to setup your configuration in a initializer you would import the config/environment file to have access to your login information.

import env from '../../config/environment';

 window.EmberENV['ember-oauth2'] = {
   model: env.APP.MODEL,
   google: {
     clientId: 'foobar',
     authBaseUri: env.APP.AUTH_BASE_URI,
     logoutUri: env.APP.CAS_LOGOUT_URI,
     redirectUri: env.APP.REDIRECT_URI,
     currentUser: env.APP.CURRENT_USER
   }
 };

The RediredctURI should be wherever your OAuth2 endpoint should redirect back to your app. The OAuth2 end point should respond with the scope, access_token, and state params.

I recommend taking a look at ember-token-auth which implements many of the default login features required to use ember-oauth2. If you look at the test/dummy app it shows how to use ember-oauth2 in an EmberCLI app.

AlbertGazizov commented 9 years ago

Thanks, @amkirwan I've successfully configured the library but stuck on the Authorization step https://github.com/amkirwan/ember-oauth2#authorization. In the Readme there is a template that uses the global App variable: window.opener.App.oauth.trigger('redirect', hash); But the App variable is not available in ember-cli apps, so this approach doesn't work. How can I rewrite this template to make it working with ember-cli apps?

amkirwan commented 9 years ago

There are a couple of ways to handle it but I think using a redirect handler is best.

Using the examples here when the redirect url for the app is called it will first load the redirect-handler.js file which calls the model RedirectHandler. If there is a window.opener, it sends the url and the configured env.APP.POSTMESSAGE_URI to make sure the message came from the url expected. env.APP.POSTMESSAGE_URI should be the url of your app.

app/initializers/redirect-handler.js

import RedirectHandler from '../models/redirect-handler';

export function initialize(registry, app) {
  app.deferReadiness();    
  RedirectHandler.handle(window.location.toString()).catch(function(){
    app.advanceReadiness();
  });
}

export default {
  name: 'redirect-callback',
  before: 'session',
  initialize: initialize
};

app/models/redirect-handler.js

import Ember from 'ember';
import env from '../../config/environment';

var RedirectHandler = Ember.Object.extend({ 

  url: null,

  run: function() {          
    return new Ember.RSVP.Promise((resolve, reject) => { 
      if (window.opener) {
        var data = '__redirect_message:' + this.get('url'); 
        return resolve(window.opener.postMessage(data, env.APP.POSTMESSAGE_URI));
      } else {
        return reject('No window.opener');
      }
    });
  } 
});

RedirectHandler.reopenClass({
   handle: function(url) {
    var handler = RedirectHandler.create({ url: url });
    return handler.run();
  }
});

export default RedirectHandler;

app/initializers/ember-oauth2.js

export function initialize(registry, app) {
  OAuth2.reopen({
    openWindow: function(url) {
      var params = authPopup.params();
      var dialog = window.open(url, "Authorize", "location=1,toolbar=0," + params);
      return new Ember.RSVP.Promise(function(resolve, reject) {

        if (window.focus && dialog) { dialog.focus(); }

        Ember.$(window).on('message', function(event) {
          var originalEvt = event.originalEvent;
          if (dialog) { dialog.close(); }

          if (originalEvt.origin === env.APP.POSTMESSAGE_URI) {
            var data = originalEvt.data;

            if (data) { resolve(data); }
            else { reject(new Error('Redirect url is empty.')); }

          } else {
            reject(new Error('Origin is invalid: ' + originalEvt.origin));
          }
        });
      });
    }      
  });
}

export default { 
  name: 'ember-oauth2',
  before: 'session',
  initialize: initialize
};

then from wherever you called authorize in your app you trigger('redirect') for example like this. It is taken from ember-token-auth the route - login.js

 authorize: function() {
  if (this.get('provider')) {
    var sessionCurrent = this.get('sessionCurrent');
    return sessionCurrent.authorize().then(function(response) {
      sessionCurrent.get('auth').trigger('redirect', response);
    }, function(error) {
      sessionCurrent.get('auth').trigger('error', error);
    });
  }
}