Skip to content

Commit

Permalink
Merge pull request #89 from RoundingWell/feature/ch21061-access-token
Browse files Browse the repository at this point in the history
Switch to auth0 access token
  • Loading branch information
luketlancaster committed Sep 30, 2019
2 parents 8f9952c + d0e6117 commit b542116
Show file tree
Hide file tree
Showing 15 changed files with 178 additions and 201 deletions.
176 changes: 61 additions & 115 deletions package-lock.json

Large diffs are not rendered by default.

2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -108,13 +108,13 @@
"yaml-loader": "^0.5.0"
},
"dependencies": {
"@auth0/auth0-spa-js": "^1.2.4",
"@fortawesome/fontawesome-svg-core": "^1.2.22",
"@fortawesome/pro-light-svg-icons": "^5.10.2",
"@fortawesome/pro-regular-svg-icons": "^5.10.2",
"@fortawesome/pro-solid-svg-icons": "^5.10.2",
"@roundingwellos/libphonenumber-js": "^0.4.14",
"animejs": "^3.1.0",
"auth0-js": "^9.11.3",
"backbone": "^1.4.0",
"backbone.eventrouter": "^1.0.0",
"backbone.marionette": "^4.1.0",
Expand Down
2 changes: 1 addition & 1 deletion src/assets/config.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"domain": "roundingwell-care-team.auth0.com",
"clientID": "zmfrKoBuMKsm5H4ZekNHeA4FRzIS44cz",
"client_id": "zmfrKoBuMKsm5H4ZekNHeA4FRzIS44cz",
"connection": "google-oauth2",
"name": "Salvation Clinic"
}
13 changes: 5 additions & 8 deletions src/js/app.js
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@ import Tooltip from 'js/components/tooltip';
import 'js/entities-service';

import AlertService from 'js/services/alert';
import AuthService from 'js/services/auth';
import BootstrapService from 'js/services/bootstrap';
import HistoryService from 'js/services/history';
import LastestListService from 'js/services/latest-list';
import ModalService from 'js/services/modal';
Expand All @@ -39,8 +39,8 @@ const Application = App.extend({
// Before the application starts make sure:
// - A root layout is attached
// - Global services are started
onBeforeStart({ token }) {
new AuthService({ token });
onBeforeStart({ name }) {
new BootstrapService({ name });
this.setView(new RootView());
this.getView().appView.getRegion('content').startPreloader();
this.configComponents();
Expand Down Expand Up @@ -93,13 +93,10 @@ const Application = App.extend({
},

beforeStart() {
return Radio.request('auth', 'bootstrap');
return Radio.request('bootstrap', 'fetch');
},

onStart({ name }) {
const currentOrg = Radio.request('auth', 'currentOrg');
currentOrg.set({ name });

onStart() {
// Ensure Error is the first app initialized
new ErrorApp({ region: this.getRegion('error') });

Expand Down
4 changes: 2 additions & 2 deletions src/js/apps/globals/app-frame_app.js
Original file line number Diff line number Diff line change
Expand Up @@ -83,8 +83,8 @@ export default App.extend({
},
showAppNav() {
const appNav = new AppNavView({
model: Radio.request('auth', 'currentUser'),
currentOrg: Radio.request('auth', 'currentOrg'),
model: Radio.request('bootstrap', 'currentUser'),
currentOrg: Radio.request('bootstrap', 'currentOrg'),
});

const patientsCollectionView = new AppNavCollectionView({ collection: patientsNav });
Expand Down
2 changes: 1 addition & 1 deletion src/js/apps/patients/list/patients-all_app.js
Original file line number Diff line number Diff line change
Expand Up @@ -37,7 +37,7 @@ export default App.extend({
this.showChildView('filters', groupsSelect);
},
_getGroups() {
const currentClinician = Radio.request('auth', 'currentUser');
const currentClinician = Radio.request('bootstrap', 'currentUser');
return currentClinician.getGroups();
},
});
4 changes: 2 additions & 2 deletions src/js/apps/patients/patient/action/action_app.js
Original file line number Diff line number Diff line change
Expand Up @@ -7,8 +7,8 @@ import App from 'js/base/app';
export default App.extend({
beforeStart({ actionId, patientId }) {
if (!actionId) {
const currentUser = Radio.request('auth', 'currentUser');
const currentOrg = Radio.request('auth', 'currentOrg');
const currentUser = Radio.request('bootstrap', 'currentUser');
const currentOrg = Radio.request('bootstrap', 'currentOrg');
const states = currentOrg.getStates();

return Radio.request('entities', 'actions:model', {
Expand Down
2 changes: 1 addition & 1 deletion src/js/apps/patients/view/view_app.js
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@ export default App.extend({
if (this.isRestarting()) return;
this.viewId = viewId;

this.currentClinician = Radio.request('auth', 'currentUser');
this.currentClinician = Radio.request('bootstrap', 'currentUser');
this.groups = this.currentClinician.getGroups();

this.showView(new LayoutView({ viewId }));
Expand Down
116 changes: 78 additions & 38 deletions src/js/auth.js
Original file line number Diff line number Diff line change
@@ -1,39 +1,19 @@
import auth0 from 'auth0-js';
import $ from 'jquery';
import createAuth0Client from '@auth0/auth0-spa-js';

const AUTHD_PATH = '/authenticated';

let webAuth;

function authorize(connection, prompt = 'none') {
webAuth.authorize({
responseType: 'id_token',
responseMode: 'fragment',
redirectUri: window.location.origin + AUTHD_PATH,
connection,
prompt,
});
}
let auth0;

/*
* authenticate parses the implicit flow hash to determine the token
* if there is an error it forces a new authorization with a new login
* If successful, redirects to the initial path and sends the app
* the token and config org name
*/
function authenticate(success, { name, connection }) {
webAuth.parseHash({}, (authErr, authResult) => {
if (authErr) {
authorize(connection, 'login');
return;
}

window.history.replaceState({}, document.title, localStorage.getItem('redirectPath') || '/');
localStorage.removeItem('redirectPath');

success({
token: authResult.idToken,
name,
});
function authenticate(success, { name }) {
return auth0.handleRedirectCallback().then(({ appState }) => {
ajaxSetup();
window.history.replaceState({}, document.title, appState);
success({ name });
});
}

Expand All @@ -43,26 +23,86 @@ function authenticate(success, { name, connection }) {
* And authenticating authorization if auth0 redirected to AUTHD_PATH
*/
function login(success, config) {
webAuth = new auth0.WebAuth(config);
const AUTHD_PATH = '/authenticated';
config.redirect_uri = location.origin + AUTHD_PATH;

createAuth0Client(config).then(auth0Client => {
auth0 = auth0Client;

if (window.location.pathname === AUTHD_PATH) {
return authenticate(success, config);
}
if (location.pathname === '/logout') {
logout();
return;
}

// RWell specific login
if (location.pathname === '/rw') {
rwellLogin();
return;
}

localStorage.setItem('redirectPath', window.location.pathname);
if (location.pathname === AUTHD_PATH) {
authenticate(success, config).catch(forceLogin);
return;
}

authorize(config.connection);
auth0.loginWithRedirect({
appState: location.pathname,
prompt: 'none',
});
});
}

function logout() {
localStorage.removeItem('config');
webAuth.logout({
returnTo: window.location.origin,
auth0.logout();
}

function rwellLogin() {
auth0.loginWithRedirect({
appState: '/',
connection: 'google-oauth2',
prompt: 'login',
});
}

function forceLogin() {
auth0.loginWithRedirect({
appState: '/',
prompt: 'login',
});
}

function ajaxSetup() {
$(document).ajaxSend((event, jqxhr, settings) => {
const origXhr = settings.xhr;
settings.xhr = function() {
const xhr = origXhr();
const origSend = xhr.send;
xhr.send = function() {
const args = arguments;
auth0
.getTokenSilently()
.then(token => {
if (xhr.readyState === 1) {
xhr.setRequestHeader('Authorization', `Bearer ${ token }`);
origSend.apply(xhr, args);
}
})
.catch(forceLogin);
};
return xhr;
};
});

$.ajaxSetup({
contentType: 'application/vnd.api+json',
statusCode: {
401: logout,
403: logout,
},
});
}

export {
login,
logout,
};

4 changes: 2 additions & 2 deletions src/js/config.js
Original file line number Diff line number Diff line change
@@ -1,8 +1,8 @@
import $ from 'jquery';

function fetchConfig(success) {
function fetchConfig(success, configVersion) {
$.getJSON('/config.json').then(config => {
localStorage.setItem('config', JSON.stringify(config));
localStorage.setItem(`config${ configVersion }`, JSON.stringify(config));
success(config);
});
}
Expand Down
20 changes: 13 additions & 7 deletions src/js/index.js
Original file line number Diff line number Diff line change
@@ -1,6 +1,9 @@
import _ from 'underscore';
import Radio from 'backbone.radio';
import 'js/utils/formatting';

const configVersion = '2';

function start(opts) {
const isForm = _.startsWith(window.location.pathname, '/formapp/');

Expand Down Expand Up @@ -28,13 +31,19 @@ function startApp({ token, name }) {

function startAuth(config) {
import(/* webpackPrefetch: true, webpackChunkName: "auth" */ './auth')
.then(({ login }) => {
.then(({ login, logout }) => {
login(start, config);
Radio.reply('auth', {
logout() {
localStorage.removeItem(`config${ configVersion }`);
logout();
},
});
});
}

function getConfig() {
const config = localStorage.getItem('config');
const config = localStorage.getItem(`config${ configVersion }`);

if (config) {
startAuth(JSON.parse(config));
Expand All @@ -43,16 +52,13 @@ function getConfig() {

import(/* webpackChunkName: "config" */'./config')
.then(({ fetchConfig }) => {
fetchConfig(startAuth);
fetchConfig(startAuth, configVersion);
});
}

document.addEventListener('DOMContentLoaded', () => {
if (_DEVELOP_ && sessionStorage.getItem('cypress')) {
start({
token: sessionStorage.getItem('cypress'),
name: 'Cypress Clinic',
});
start({ name: 'Cypress Clinic' });
return;
}

Expand Down
24 changes: 6 additions & 18 deletions src/js/services/auth.js → src/js/services/bootstrap.js
Original file line number Diff line number Diff line change
Expand Up @@ -3,43 +3,31 @@ import Radio from 'backbone.radio';

import App from 'js/base/app';

import { logout } from 'js/auth';

export default App.extend({
channelName: 'auth',
channelName: 'bootstrap',
radioRequests: {
'currentUser': 'getCurrentUser',
'currentOrg': 'getCurrentOrg',
'logout': logout,
'bootstrap': 'initBootstrap',
'fetch': 'fetchBootstrap',
},
initialize({ token }) {
$.ajaxSetup({
contentType: 'application/vnd.api+json',
statusCode: {
401: logout,
403: logout,
},
beforeSend(request) {
request.setRequestHeader('Authorization', `Bearer ${ token }`);
},
});
initialize({ name }) {
this.currentOrg = Radio.request('entities', 'organizations:model', { name });
},
getCurrentUser() {
return this.currentUser;
},
getCurrentOrg() {
return this.currentOrg;
},
initBootstrap() {
fetchBootstrap() {
const d = $.Deferred();
const fetchCurrentUser = Radio.request('entities', 'fetch:clinicians:current');
const fetchGroups = Radio.request('entities', 'fetch:groups:collection');
const fetchRoles = Radio.request('entities', 'fetch:roles:collection');
const fetchStates = Radio.request('entities', 'fetch:states:collection');
$.when(fetchCurrentUser, fetchRoles, fetchStates, fetchGroups).done((currentUser, roles, states) => {
this.currentUser = currentUser;
this.currentOrg = Radio.request('entities', 'organizations:model', {
this.currentOrg.set({
states: states[0],
roles: roles[0],
});
Expand Down
2 changes: 1 addition & 1 deletion src/js/views/globals/app-nav/app-nav_views.js
Original file line number Diff line number Diff line change
Expand Up @@ -89,7 +89,7 @@ const NavItemView = View.extend({
},
templateContext: {
role() {
const clinician = Radio.request('auth', 'currentUser');
const clinician = Radio.request('bootstrap', 'currentUser');
return clinician.getRole().get('name');
},
},
Expand Down
6 changes: 3 additions & 3 deletions src/js/views/patients/actions/actions_views.js
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,7 @@ const StateTemplate = hbs`<span class="action--{{ statusClass }}">{{fas statusIc
const StateComponent = Droplist.extend({
isCompact: false,
initialize({ model }) {
const currentOrg = Radio.request('auth', 'currentOrg');
const currentOrg = Radio.request('bootstrap', 'currentOrg');
this.collection = currentOrg.getStates();
this.setState({ selected: this.collection.get(model.get('_state')) });
},
Expand Down Expand Up @@ -109,9 +109,9 @@ const OwnerComponent = Droplist.extend({
};
},
initialize({ model }) {
const currentOrg = Radio.request('auth', 'currentOrg');
const currentOrg = Radio.request('bootstrap', 'currentOrg');
const roles = currentOrg.getRoles();
const currentUser = Radio.request('auth', 'currentUser');
const currentUser = Radio.request('bootstrap', 'currentUser');
const groups = currentUser.getGroups();

this.lists = groups.map(group => {
Expand Down
2 changes: 1 addition & 1 deletion src/js/views/patients/view/view_views.js
Original file line number Diff line number Diff line change
Expand Up @@ -110,7 +110,7 @@ const LayoutView = View.extend({
<div class="flex-region list-page__list js-list" data-list-region></div>
`,
templateContext() {
const currentClinician = Radio.request('auth', 'currentUser');
const currentClinician = Radio.request('bootstrap', 'currentUser');

return {
role: currentClinician.getRole().get('name'),
Expand Down

0 comments on commit b542116

Please sign in to comment.