ember.jsember-cliember-simple-auth

Fixing custom authenticator's restore method


I'm using ember-simple-auth and a custom authenticator for an HTTP basic login with CSRF protection. Everything is working fine except sometimes my restore method resolves when it should be failing, like when the session expires.

When authentication succeeds I resolve with the csrf token, but then when the token or session expires and I refresh the page, the resolve method still succeeds because all I'm doing is checking if the token is still there (not if it's valid). I know this is wrong, so I guess my question would be what is the proper way to handle this? Should I also be resolving with the session id? Should I be sending an AJAX request in the restore method with the stored token to see if it is still valid and returns success? I'm interested in hearing about any other improvements I could make as well.

Here is my authenticator code:

import Ember from 'ember';
import ENV from 'criteria-manager/config/environment';
import Base from 'ember-simple-auth/authenticators/base';

export default Base.extend({

    restore(data) {
        return new Ember.RSVP.Promise((resolve, reject) => {
            if (data.token) {
                Ember.$.ajaxSetup({
                    headers: {
                        'X-XSRF-TOKEN': data.token
                    }
                });
                resolve(data);
            }
            else {
                reject();
            }
        });
    },
    authenticate(credentials) {
        let csrfToken = this.getCookie('XSRF-TOKEN');
        return new Ember.RSVP.Promise((resolve, reject) => {
            Ember.$.ajax({
                beforeSend: function(xhr) {
                    xhr.setRequestHeader("Authorization", "Basic " + btoa(credentials.username + ":" + credentials.password));
                    xhr.setRequestHeader("X-XSRF-TOKEN", csrfToken);
                },
                url: ENV.host + "/api/users/login",
                method: 'POST'
            }).done(() => {
                //A new CSRF token is issued after login, add it to future AJAX requests
                Ember.$.ajaxSetup({
                    headers: {
                        'X-XSRF-TOKEN': this.getCookie('XSRF-TOKEN')
                    }
                });
                Ember.run(() => {
                    resolve({
                        token: this.getCookie('XSRF-TOKEN')
                    });
                });
            }).fail((xhr) => {
                Ember.run(() => {
                    if(xhr.status === 0) {
                        reject("Please check your internet connection!");
                    }
                    else if (xhr.status === 401) {
                        reject("Invalid username and/or password.");
                    }
                    else {
                        reject("Error: Http Status Code " + xhr.status);
                    }
                });
            });
        });
    },
    invalidate() {
        return new Ember.RSVP.Promise((resolve, reject) => {
            let csrfToken = this.getCookie('XSRF-TOKEN');
            Ember.$.ajax({
                beforeSend: function(xhr) {
                    xhr.setRequestHeader("X-XSRF-TOKEN", csrfToken);
                },
                url: ENV.host + '/logout',
                method: 'POST'
            }).done(() => {
                Ember.run(() => {
                    resolve();
                });
            }).fail(() => {
                Ember.run(() => {
                    reject();
                });
            });
        });
    },
    getCookie(name) {
        let alLCookies = "; " + document.cookie;
        let cookieArray = alLCookies.split("; " + name + "=");
        if (cookieArray.length === 2) {
            return cookieArray.pop().split(";").shift();
        }
    }
});

Solution

  • Should I also be resolving with the session id? Should I be sending an AJAX request in the restore method with the stored token to see if it is still valid and returns success?

    It all depends on your project's needs. In my opinion it's good to check if token is still valid. For example, oauth2-password-grant stores expiring date in session and when restoring simply compares it with current time. You may do this too. Or, if your backend has some token validation endpoint, you may send request to be sure if token is valid.