From 5a1f93975ccfc8c97f6bf16a73ac6b3e50a627da Mon Sep 17 00:00:00 2001 From: Wyatt Johnson Date: Mon, 22 Oct 2018 12:13:15 -0600 Subject: [PATCH] feat: added support for access_token hash passthrough --- client/coral-framework/actions/auth.js | 20 +++++---------- client/coral-framework/services/auth.js | 11 +++++++++ client/coral-framework/services/bootstrap.js | 26 +++++++++++++++++++- 3 files changed, 42 insertions(+), 15 deletions(-) create mode 100644 client/coral-framework/services/auth.js diff --git a/client/coral-framework/actions/auth.js b/client/coral-framework/actions/auth.js index 20aa4ce57..bf7964cf9 100644 --- a/client/coral-framework/actions/auth.js +++ b/client/coral-framework/actions/auth.js @@ -1,10 +1,5 @@ import * as actions from '../constants/auth'; -import jwtDecode from 'jwt-decode'; - -function cleanAuthData(localStorage) { - localStorage.removeItem('token'); - localStorage.removeItem('exp'); -} +import { setStorageAuthToken, clearStorageAuthToken } from '../services/auth'; export const checkLogin = () => ( dispatch, @@ -15,7 +10,7 @@ export const checkLogin = () => ( rest('/auth') .then(result => { if (!result.user) { - cleanAuthData(localStorage); + clearStorageAuthToken(localStorage); dispatch(checkLoginSuccess(null)); client.resetWebsocket(); return; @@ -32,7 +27,7 @@ export const checkLogin = () => ( .catch(error => { if (error.status && error.status === 401 && localStorage) { // Unauthorized. - cleanAuthData(localStorage); + clearStorageAuthToken(localStorage); client.resetWebsocket(); } else { console.error(error); @@ -58,8 +53,7 @@ export const setAuthToken = token => ( _, { localStorage, client } ) => { - localStorage.setItem('exp', jwtDecode(token).exp); - localStorage.setItem('token', token); + setStorageAuthToken(localStorage, token); // Dispatch the set auth token action. For some browsers and situations, we // may not be able to persist the auth token any other way. Keep it in redux! @@ -76,9 +70,7 @@ export const handleSuccessfulLogin = (user, token) => ( _, { client, localStorage, postMessage } ) => { - const { exp } = jwtDecode(token); - localStorage.setItem('exp', exp); - localStorage.setItem('token', token); + setStorageAuthToken(localStorage, token); // Send the message via the messages service to the window.opener if it // exists. @@ -117,7 +109,7 @@ export const logout = () => async ( } // Clear the auth data persisted to localStorage. - cleanAuthData(localStorage); + clearStorageAuthToken(localStorage); // Reset the websocket. client.resetWebsocket(); diff --git a/client/coral-framework/services/auth.js b/client/coral-framework/services/auth.js new file mode 100644 index 000000000..a23a6dd0d --- /dev/null +++ b/client/coral-framework/services/auth.js @@ -0,0 +1,11 @@ +import jwtDecode from 'jwt-decode'; + +export const setStorageAuthToken = (storage, token) => { + storage.setItem('exp', jwtDecode(token).exp); + storage.setItem('token', token); +}; + +export const clearStorageAuthToken = storage => { + storage.removeItem('token'); + storage.removeItem('exp'); +}; diff --git a/client/coral-framework/services/bootstrap.js b/client/coral-framework/services/bootstrap.js index c96893d4e..c7e00bbaa 100644 --- a/client/coral-framework/services/bootstrap.js +++ b/client/coral-framework/services/bootstrap.js @@ -22,6 +22,7 @@ import { } from 'coral-framework/services/storage'; import { createHistory } from 'coral-framework/services/history'; import { createIntrospection } from 'coral-framework/services/introspection'; +import { setStorageAuthToken } from 'coral-framework/services/auth'; import introspectionData from 'coral-framework/graphql/introspection.json'; import coreReducers from '../reducers'; import { checkLogin as checkLoginAction } from '../actions/auth'; @@ -46,9 +47,32 @@ const getAuthToken = (store, storage) => { // capable of storing the token in localStorage, then we would have // persisted it to the redux state. return state.config.auth_token || state.auth.token; - } else if (!bowser.safari && !bowser.ios && storage) { + } else if ( + !bowser.safari && + !bowser.ios && + storage && + storage.getItem('token') + ) { // Use local storage auth tokens where there's a stable api. return storage.getItem('token'); + } else if (location.hash && location.hash.startsWith('#access_token=')) { + // Check to see if the access token is living in the URL as a hash. + const token = location.hash.substring(14); + + history.replaceState( + {}, + document.title, + window.location.pathname + window.location.search + ); + + // Once we clear the hash above, this login method will not persist across + // refreshes. We will need to persist the token to storage if it's + // available. + if (storage) { + setStorageAuthToken(storage, token); + } + + return token; } return null;