Permalink
Browse files

refactor(authService): consistent redirect, oauth moved to authentica…

…tion

BREAKING CHANGE: for AuthService(provider, redirectUri, userData) redirectUri===false means "Do not redirect" now. Set redirectUrl to undefined or null to use the defaultRedirectUrl.(which is in this case  BaseConfig.loginRedirect)
DEPRECATED: for AuthService(provider, redirectUri, userData) redirectUri === true to actually not redirect is deprecated. Set redirectUrl===false instead.
  • Loading branch information...
doktordirk committed Apr 10, 2016
1 parent 194a74d commit 2c15244ba31a5422708540a5a139f408f9240756
Showing with 125 additions and 89 deletions.
  1. +37 −33 src/authService.js
  2. +55 −18 src/authentication.js
  3. +21 −38 test/authService.spec.js
  4. +12 −0 test/authentication.spec.js
@@ -2,15 +2,11 @@ import {inject} from 'aurelia-dependency-injection';
import {Authentication} from './authentication';
import {BaseConfig} from './baseConfig';
import {OAuth1} from './oAuth1';
import {OAuth2} from './oAuth2';
@inject(Authentication, OAuth1, OAuth2, BaseConfig)
@inject(Authentication, BaseConfig)
export class AuthService {
constructor(authentication, oAuth1, oAuth2, config) {
constructor(authentication, config) {
this.authentication = authentication;
this.oAuth1 = oAuth1;
this.oAuth2 = oAuth2;
this.config = config;
}
@@ -156,14 +152,14 @@ export class AuthService {
return this._signup(content);
}
_signup(data) {
_signup(data, redirectUri) {
return this.client.post(this.config.withBase(this.config.signupUrl), data)
.then(response => {
if (this.config.loginOnSignup) {
this.authentication.setAccessTokenFromResponse(response);
} else if (this.config.signupRedirect) {
window.location.href = this.config.signupRedirect;
this.authentication.setTokensFromResponse(response);
}
this.authentication.redirect(redirectUri, this.config.signupRedirect);
return response;
});
}
@@ -189,17 +185,16 @@ export class AuthService {
return this._login(content);
}
_login(data) {
_login(data, redirectUri) {
if (this.config.clientId) {
data.client_id = this.config.clientId;
}
return this.client.post(this.config.withBase(this.config.loginUrl), data)
.then(response => {
this.authentication.setAccessTokenFromResponse(response);
if (this.config.useRefreshToken) {
this.authentication.setRefreshTokenFromResponse(response);
}
this.authentication.setTokensFromResponse(response);
this.authentication.redirect(redirectUri, this.config.loginRedirect);
return response;
});
@@ -214,7 +209,12 @@ export class AuthService {
*
*/
logout(redirectUri) {
return this.authentication.logout(redirectUri);
return this.authentication.logout(redirectUri)
.then(response => {
this.authentication.redirect(redirectUri, this.config.logoutRedirect);
return response;
});
}
/**
@@ -224,9 +224,9 @@ export class AuthService {
*
*/
updateToken() {
this.isRefreshing = true;
const refreshToken = this.authentication.refreshToken;
let content = {};
this.isRefreshing = true;
const refreshToken = this.authentication.refreshToken;
let content = {};
if (refreshToken) {
content = {grant_type: 'refresh_token', refresh_token: refreshToken};
@@ -236,17 +236,15 @@ export class AuthService {
return this.client.post(this.config.withBase(this.config.loginUrl), content)
.then(response => {
this.authentication.setRefreshTokenFromResponse(response);
this.authentication.setAccessTokenFromResponse(response);
this.isRefreshing = false;
this.authentication.setTokensFromResponse(response);
return response;
}).catch(err => {
this.authentication.accessToken = null;
this.authentication.refreshToken = null;
this.isRefreshing = false;
this.authentication.removeTokens();
throw err;
})
.then(response => {
this.isRefreshing = false;
return response;
});
}
@@ -264,11 +262,12 @@ export class AuthService {
*
*/
authenticate(name, redirectUri, userData = {}) {
const provider = this.config.providers[name].type === '1.0' ? this.oAuth1 : this.oAuth2;
return provider.open(this.config.providers[name], userData)
return this.authentication.authenticate(name, userData)
.then(response => {
this.authentication.setAccessTokenFromResponse(response, redirectUri);
this.authentication.setTokensFromResponse(response);
this.authentication.redirect(redirectUri, this.config.loginRedirect);
return response;
});
}
@@ -281,8 +280,13 @@ export class AuthService {
* @return {Promise<response>}
*
*/
unlink(name) {
unlink(name, redirectUri) {
const unlinkUrl = this.config.withBase(this.config.unlinkUrl) + name;
return this.client.request(this.config.unlinkMethod, unlinkUrl);
return this.client.request(this.config.unlinkMethod, unlinkUrl)
.then(response => {
this.authentication.redirect(redirectUri);
return response;
});
}
}
@@ -2,12 +2,16 @@ import {inject} from 'aurelia-dependency-injection';
import {BaseConfig} from './baseConfig';
import {Storage} from './storage';
import {OAuth1} from './oAuth1';
import {OAuth2} from './oAuth2';
@inject(Storage, BaseConfig)
@inject(Storage, BaseConfig, OAuth1, OAuth2)
export class Authentication {
constructor(storage, config) {
constructor(storage, config, oAuth1, oAuth2) {
this.storage = storage;
this.config = config;
this.oAuth1 = oAuth1;
this.oAuth2 = oAuth2;
}
getLoginRoute() {
@@ -128,19 +132,13 @@ export class Authentication {
return response[tokenName] === undefined ? null : response[tokenName];
}
setAccessTokenFromResponse(response, redirect) {
setAccessTokenFromResponse(response) {
const config = this.config;
const newToken = this.getTokenFromResponse(response, config.accessTokenProp, config.accessTokenName, config.accessTokenRoot);
if (!newToken) throw new Error('Token not found in response');
this.accessToken = newToken;
if (this.config.loginRedirect && !redirect) {
window.location.href = this.config.loginRedirect;
} else if (typeof redirect === 'string') {
window.location.href = window.encodeURI(redirect);
}
}
setRefreshTokenFromResponse(response) {
@@ -152,18 +150,57 @@ export class Authentication {
this.refreshToken = newToken;
}
logout(redirect) {
return new Promise(resolve => {
this.accessToken = null;
this.refreshToken = null;
setTokensFromResponse(response) {
this.setAccessTokenFromResponse(response);
if (this.config.logoutRedirect && !redirect) {
window.location.href = this.config.logoutRedirect;
} else if (typeof redirect === 'string') {
window.location.href = redirect;
}
if (this.config.useRefreshToken) {
this.setRefreshTokenFromResponse(response);
}
}
removeTokens() {
this.accessToken = null;
this.refreshToken = null;
}
logout() {
return new Promise(resolve => {
this.removeTokens();
resolve();
});
}
/**
* Authenticate with third-party
*
* @param {String} name of the provider
* @param {[{}]} [userData]
*
* @return {Promise<response>}
*
*/
authenticate(name, userData = {}) {
const provider = this.config.providers[name].type === '1.0' ? this.oAuth1 : this.oAuth2;
return provider.open(this.config.providers[name], userData);
}
redirect(redirectUrl, defaultRedirectUrl) {
// stupid rule to keep it BC
if (redirectUrl === true) {
console.warn('Setting redirectUrl === true to actually not redirect is deprecated. Set redirectUrl===false instead.');
return;
}
// explicit false means don't redirect
if (redirectUrl === false) {
console.warn('Setting redirectUrl === false to actually use the defaultRedirectUrl has changed. It means "Do not redirect" now. Set redirectUrl to undefined or null to use the defaultRedirectUrl.');
return;
}
if (typeof redirectUrl === 'string') {
window.location.href = window.encodeURI(redirectUrl);
} else if (defaultRedirectUrl) {
window.location.href = defaultRedirectUrl;
}
}
}
@@ -235,7 +235,7 @@ describe('AuthService', () => {
});
it('Should unlink provider using POST.', (done) => {
const container = getContainer();
const container = getContainer();
const authService = container.get(AuthService);
authService.config.unlinkMethod = 'post';
@@ -254,39 +254,30 @@ describe('AuthService', () => {
});
describe('.authenticate()', () => {
let oAuth1;
let oAuth2;
beforeEach(() => {
oAuth1 = {
open: (provider, userData) => Promise.resolve({
provider: provider,
userData: userData,
access_token: 'oauth1'
})
};
oAuth2 = {
open: (provider, userData) => Promise.resolve({
provider: provider,
userData: userData,
access_token: 'oauth2'
})
};
const container = getContainer();
const authentication = container.get(Authentication);
const baseConfig = container.get(BaseConfig);
authentication.oAuth1.open = (provider, userData) => Promise.resolve({
provider: provider,
userData: userData,
access_token: 'oauth1'
});
authentication.oAuth2.open = (provider, userData) => Promise.resolve({
provider: provider,
userData: userData,
access_token: 'oauth2'
});
afterEach((done) => {
const container = getContainer();
const authService = container.get(AuthService);
authService.logout().then(done);
});
it('Should authenticate with oAuth1 provider and login.', (done) => {
const container = getContainer();
const baseConfig = container.get(BaseConfig);
const authentication = container.get(Authentication);
const authService = new AuthService(authentication, oAuth1, oAuth2, baseConfig);
spyOn(oAuth1, 'open').and.callThrough();
const authService = new AuthService(authentication, baseConfig);
spyOn(authentication.oAuth1, 'open').and.callThrough();
authService.authenticate('twitter', null, {data: 'some'})
.then(response => {
@@ -308,12 +299,8 @@ describe('AuthService', () => {
});
it('Should authenticate with oAuth2 provider and login.', (done) => {
const container = getContainer();
const baseConfig = container.get(BaseConfig);
const authentication = container.get(Authentication);
const authService = new AuthService(authentication, oAuth1, oAuth2, baseConfig);
spyOn(oAuth2, 'open').and.callThrough();
const authService = new AuthService(authentication, baseConfig);
spyOn(authentication.oAuth2, 'open').and.callThrough();
authService.authenticate('facebook', null, {data: 'some'})
.then(response => {
@@ -335,12 +322,8 @@ describe('AuthService', () => {
});
it('Should try to authenticate with and fail.', (done) => {
const container = getContainer();
const baseConfig = container.get(BaseConfig);
const authentication = container.get(Authentication);
const authService = new AuthService(authentication, oAuth1, oAuth2, baseConfig);
spyOn(oAuth2, 'open').and.returnValue(Promise.resolve());
const authService = new AuthService(authentication, baseConfig);
spyOn(authentication.oAuth2, 'open').and.returnValue(Promise.resolve());
authService.authenticate('facebook')
.then(res => {
@@ -276,4 +276,16 @@ describe('Authentication', () => {
});
});
});
describe('.redirect', () => {
const container = new Container();
const authentication = container.get(Authentication);
it('should not redirect with redirectUri===false', () => {
authentication.redirect(false, 'somewhere');
// basically just don't get the window reload error
expect(true).toBe(true);
});
});
});

0 comments on commit 2c15244

Please sign in to comment.