Search code examples
ember.jsoauth-2.0ember-simple-auth

Restore session without email and password using Oauth2 token


I have a situation where I want to be able to automatically log in a user based on a confirmation token parameter in the URL. In my route I am making an AJAX request to the server to validate the token and sending back the same serialized Oauth2 JSON that is used for logging in.

Is it possible to log the user in with this token?

First the user goes to a URL like:

http://example.com/users/confirmation?confirmation_token=eisz6LMzmck55xHuqopF

Next my route sends an AJAX request to the server which replies with the Oauth2 token.

Here is my current implementation trying to use the authenticator to restore it. Despite seeing "I should be logged in" in the console, it's not working. I suspect this is because it does not know to restore the session. Looking at the session documentation, I see a public method to manually authenticate, but not one to restore from the oauth token.

import Ember from 'ember';
import ajax from 'ic-ajax';

export default Ember.Route.extend({
  model: function(params) {
    var path = MyApp.API_NAMESPACE + '/confirmation?confirmation_token=' + params.confirmation_token;
    var authenticator = this.container.lookup('simple-auth-authenticator:oauth2-password-grant');

    return ajax(path).then(function(response) {
      return authenticator.restore(response).then(function() {
        console.log('I should be logged in');
      });
    }).catch(function(request) {
      console.log(request);
    });
  }
});

Solution

  • I solved this by creating a custom authenticator that essentially inherits from the oauth2 authenticator, overriding just the authenticate method.

    First I created my authenticator in app/lib/confirmation-authenticator.js:

    import OAuth2Authenticator from 'simple-auth-oauth2/authenticators/oauth2';
    import ajax from 'ic-ajax';
    
    export default OAuth2Authenticator.extend({
      authenticate: function(token) {
        var path = MyApp.API_NAMESPACE + '/confirmation?confirmation_token=' + token;
    
        return new Ember.RSVP.Promise(function(resolve, reject) {
          ajax(path).then(function(response) {
            resolve(response);
          }).catch(function(request) {
            reject(request.textStatus);
          });
        });
      }
    });
    

    Then register the authenticator in my initializer at app/initializers/authentication:

    import ConfirmationAuthenticator from 'my-app/lib/confirmation-authenticator';
    
    export default {
      name: 'authentication',
      before: 'simple-auth',
    
      initialize: function(container) {
        container.register('simple-auth-authenticator:confirmation', ConfirmationAuthenticator);
    
        window.ENV = window.ENV || {};
    
        window.ENV['simple-auth'] = {
          authorizer: 'simple-auth-authorizer:oauth2-bearer',
        };
    
        window.ENV['simple-auth-oauth2'] = {
          serverTokenEndpoint: MyApp.API_NAMESPACE + '/oauth/token'
        };
      }
    };
    

    And finally my route at app/routes/users/confirmation.js:

    import Ember from 'ember';
    
    export default Ember.Route.extend({
      model: function(params) {
        var token = params.confirmation_token;
    
        return this.get('session').authenticate('simple-auth-authenticator:confirmation', token);
      }
    });