Save auth tokens from link shares only in memory, don't persist them to localStorage
Resolves #587
This commit is contained in:
parent
aebfde0c74
commit
a787f6ffc7
4 changed files with 78 additions and 25 deletions
62
src/helpers/auth.js
Normal file
62
src/helpers/auth.js
Normal file
|
@ -0,0 +1,62 @@
|
||||||
|
import {HTTPFactory} from '@/http-common'
|
||||||
|
|
||||||
|
let savedToken = null
|
||||||
|
let persisted = false
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Saves a token while optionally saving it to lacal storage. This is used when viewing a link share:
|
||||||
|
* It enables viewing multiple link shares indipendently from each in multiple tabs other without overriding any other open ones.
|
||||||
|
* @param token
|
||||||
|
* @param persist
|
||||||
|
*/
|
||||||
|
export const saveToken = (token, persist = true) => {
|
||||||
|
savedToken = token
|
||||||
|
if (persist) {
|
||||||
|
persisted = true
|
||||||
|
localStorage.setItem('token', token)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns a saved token. If there is one saved in memory it will use that before anything else.
|
||||||
|
* @returns {string|null}
|
||||||
|
*/
|
||||||
|
export const getToken = () => {
|
||||||
|
if (savedToken !== null) {
|
||||||
|
return savedToken
|
||||||
|
}
|
||||||
|
|
||||||
|
savedToken = localStorage.getItem('token')
|
||||||
|
return savedToken
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Removes all tokens everywhere.
|
||||||
|
*/
|
||||||
|
export const removeToken = () => {
|
||||||
|
savedToken = null
|
||||||
|
localStorage.removeItem('token')
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Refreshes an auth token while ensuring it is updated everywhere.
|
||||||
|
* @returns {Promise<AxiosResponse<any>>}
|
||||||
|
*/
|
||||||
|
export const refreshToken = () => {
|
||||||
|
const HTTP = HTTPFactory()
|
||||||
|
return HTTP.post('user/token', null, {
|
||||||
|
headers: {
|
||||||
|
Authorization: `Bearer ${getToken()}`,
|
||||||
|
},
|
||||||
|
})
|
||||||
|
.then(r => {
|
||||||
|
saveToken(r.data.token, persisted)
|
||||||
|
return Promise.resolve(r)
|
||||||
|
})
|
||||||
|
.catch(e => {
|
||||||
|
// eslint-disable-next-line
|
||||||
|
console.log('Error renewing token: ', e)
|
||||||
|
return Promise.reject(e)
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
|
@ -2,6 +2,7 @@
|
||||||
|
|
||||||
import {register} from 'register-service-worker'
|
import {register} from 'register-service-worker'
|
||||||
import swEvents from './ServiceWorker/events'
|
import swEvents from './ServiceWorker/events'
|
||||||
|
import {getToken} from './helpers/auth'
|
||||||
|
|
||||||
if (process.env.NODE_ENV === 'production') {
|
if (process.env.NODE_ENV === 'production') {
|
||||||
register(`${process.env.BASE_URL}sw.js`, {
|
register(`${process.env.BASE_URL}sw.js`, {
|
||||||
|
@ -44,7 +45,7 @@ if (navigator && navigator.serviceWorker) {
|
||||||
if (action === 'getBearerToken') {
|
if (action === 'getBearerToken') {
|
||||||
console.debug('Token request from sw')
|
console.debug('Token request from sw')
|
||||||
port.postMessage({
|
port.postMessage({
|
||||||
authToken: localStorage.getItem('token'),
|
authToken: getToken(),
|
||||||
})
|
})
|
||||||
} else {
|
} else {
|
||||||
console.error('Unknown event', event)
|
console.error('Unknown event', event)
|
||||||
|
|
|
@ -2,6 +2,7 @@ import axios from 'axios'
|
||||||
import reduce from 'lodash/reduce'
|
import reduce from 'lodash/reduce'
|
||||||
import replace from 'lodash/replace'
|
import replace from 'lodash/replace'
|
||||||
import {objectToSnakeCase} from '@/helpers/case'
|
import {objectToSnakeCase} from '@/helpers/case'
|
||||||
|
import {getToken} from '@/helpers/auth'
|
||||||
|
|
||||||
export default class AbstractService {
|
export default class AbstractService {
|
||||||
|
|
||||||
|
@ -66,12 +67,9 @@ export default class AbstractService {
|
||||||
})
|
})
|
||||||
|
|
||||||
// Set the default auth header if we have a token
|
// Set the default auth header if we have a token
|
||||||
if (
|
const token = getToken()
|
||||||
localStorage.getItem('token') !== '' &&
|
if (token !== null) {
|
||||||
localStorage.getItem('token') !== null &&
|
this.http.defaults.headers.common['Authorization'] = `Bearer ${token}`
|
||||||
localStorage.getItem('token') !== undefined
|
|
||||||
) {
|
|
||||||
this.http.defaults.headers.common['Authorization'] = 'Bearer ' + localStorage.getItem('token')
|
|
||||||
}
|
}
|
||||||
|
|
||||||
this.paths = {
|
this.paths = {
|
||||||
|
|
|
@ -1,6 +1,7 @@
|
||||||
import {HTTPFactory} from '@/http-common'
|
import {HTTPFactory} from '@/http-common'
|
||||||
import {ERROR_MESSAGE, LOADING} from '../mutation-types'
|
import {ERROR_MESSAGE, LOADING} from '../mutation-types'
|
||||||
import UserModel from '../../models/user'
|
import UserModel from '../../models/user'
|
||||||
|
import {getToken, refreshToken, removeToken, saveToken} from '@/helpers/auth'
|
||||||
|
|
||||||
const defaultSettings = settings => {
|
const defaultSettings = settings => {
|
||||||
if (typeof settings.weekStart === 'undefined' || settings.weekStart === '') {
|
if (typeof settings.weekStart === 'undefined' || settings.weekStart === '') {
|
||||||
|
@ -60,7 +61,7 @@ export default {
|
||||||
ctx.commit(LOADING, true, {root: true})
|
ctx.commit(LOADING, true, {root: true})
|
||||||
|
|
||||||
// Delete an eventually preexisting old token
|
// Delete an eventually preexisting old token
|
||||||
localStorage.removeItem('token')
|
removeToken()
|
||||||
|
|
||||||
const data = {
|
const data = {
|
||||||
username: credentials.username,
|
username: credentials.username,
|
||||||
|
@ -74,7 +75,7 @@ export default {
|
||||||
return HTTP.post('login', data)
|
return HTTP.post('login', data)
|
||||||
.then(response => {
|
.then(response => {
|
||||||
// Save the token to local storage for later use
|
// Save the token to local storage for later use
|
||||||
localStorage.setItem('token', response.data.token)
|
saveToken(response.data.token)
|
||||||
|
|
||||||
// Tell others the user is autheticated
|
// Tell others the user is autheticated
|
||||||
ctx.commit('isLinkShareAuth', false)
|
ctx.commit('isLinkShareAuth', false)
|
||||||
|
@ -127,11 +128,11 @@ export default {
|
||||||
}
|
}
|
||||||
|
|
||||||
// Delete an eventually preexisting old token
|
// Delete an eventually preexisting old token
|
||||||
localStorage.removeItem('token')
|
removeToken()
|
||||||
return HTTP.post(`/auth/openid/${provider}/callback`, data)
|
return HTTP.post(`/auth/openid/${provider}/callback`, data)
|
||||||
.then(response => {
|
.then(response => {
|
||||||
// Save the token to local storage for later use
|
// Save the token to local storage for later use
|
||||||
localStorage.setItem('token', response.data.token)
|
saveToken(response.data.token)
|
||||||
|
|
||||||
// Tell others the user is autheticated
|
// Tell others the user is autheticated
|
||||||
ctx.commit('isLinkShareAuth', false)
|
ctx.commit('isLinkShareAuth', false)
|
||||||
|
@ -151,7 +152,7 @@ export default {
|
||||||
password: password,
|
password: password,
|
||||||
})
|
})
|
||||||
.then(r => {
|
.then(r => {
|
||||||
localStorage.setItem('token', r.data.token)
|
saveToken(r.data.token, false)
|
||||||
ctx.dispatch('checkAuth')
|
ctx.dispatch('checkAuth')
|
||||||
return Promise.resolve(r.data)
|
return Promise.resolve(r.data)
|
||||||
}).catch(e => {
|
}).catch(e => {
|
||||||
|
@ -167,7 +168,7 @@ export default {
|
||||||
return Promise.resolve()
|
return Promise.resolve()
|
||||||
}
|
}
|
||||||
|
|
||||||
const jwt = localStorage.getItem('token')
|
const jwt = getToken()
|
||||||
let authenticated = false
|
let authenticated = false
|
||||||
if (jwt) {
|
if (jwt) {
|
||||||
const base64 = jwt
|
const base64 = jwt
|
||||||
|
@ -213,24 +214,15 @@ export default {
|
||||||
},
|
},
|
||||||
// Renews the api token and saves it to local storage
|
// Renews the api token and saves it to local storage
|
||||||
renewToken(ctx) {
|
renewToken(ctx) {
|
||||||
const HTTP = HTTPFactory()
|
|
||||||
if (!ctx.state.authenticated) {
|
if (!ctx.state.authenticated) {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
HTTP.post('user/token', null, {
|
refreshToken()
|
||||||
headers: {
|
.then(() => {
|
||||||
Authorization: 'Bearer ' + localStorage.getItem('token'),
|
|
||||||
},
|
|
||||||
})
|
|
||||||
.then(r => {
|
|
||||||
localStorage.setItem('token', r.data.token)
|
|
||||||
ctx.dispatch('checkAuth')
|
ctx.dispatch('checkAuth')
|
||||||
})
|
})
|
||||||
.catch(e => {
|
.catch(e => {
|
||||||
// eslint-disable-next-line
|
|
||||||
console.log('Error renewing token: ', e)
|
|
||||||
|
|
||||||
// Don't logout on network errors as the user would then get logged out if they don't have
|
// Don't logout on network errors as the user would then get logged out if they don't have
|
||||||
// internet for a short period of time - such as when the laptop is still reconnecting
|
// internet for a short period of time - such as when the laptop is still reconnecting
|
||||||
if (e.request.status) {
|
if (e.request.status) {
|
||||||
|
@ -239,7 +231,7 @@ export default {
|
||||||
})
|
})
|
||||||
},
|
},
|
||||||
logout(ctx) {
|
logout(ctx) {
|
||||||
localStorage.removeItem('token')
|
removeToken()
|
||||||
ctx.dispatch('checkAuth')
|
ctx.dispatch('checkAuth')
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
|
Loading…
Reference in a new issue