myPrayerJournal v2 #27
src
@ -72,7 +72,8 @@ module Configure =
|
||||
fun opts ->
|
||||
let jwtCfg = cfg.GetSection "Auth0"
|
||||
opts.Authority <- sprintf "https://%s/" jwtCfg.["Domain"]
|
||||
opts.Audience <- jwtCfg.["Id"])
|
||||
opts.Audience <- jwtCfg.["Id"]
|
||||
)
|
||||
|> ignore
|
||||
sc.AddSingleton<IJsonSerializer> (NewtonsoftJsonSerializer jsonSettings)
|
||||
|> ignore
|
||||
|
@ -35,6 +35,7 @@ import Vue from 'vue'
|
||||
|
||||
import Navigation from '@/components/common/Navigation'
|
||||
|
||||
import actions from '@/store/action-types'
|
||||
import { version } from '../package.json'
|
||||
|
||||
export default {
|
||||
@ -57,21 +58,12 @@ export default {
|
||||
}
|
||||
}
|
||||
},
|
||||
async created () {
|
||||
try {
|
||||
await this.$auth.renewTokens()
|
||||
} catch (e) {
|
||||
if (e !== 'Not logged in') {
|
||||
// eslint-disable-next-line
|
||||
console.log(e)
|
||||
}
|
||||
}
|
||||
},
|
||||
mounted () {
|
||||
async mounted () {
|
||||
this.progress.events.$on('show', this.showProgress)
|
||||
this.progress.events.$on('done', this.hideProgress)
|
||||
this.snackbar.events.$on('info', this.showInfo)
|
||||
this.snackbar.events.$on('error', this.showError)
|
||||
await this.$store.dispatch(actions.CHECK_AUTHENTICATION)
|
||||
},
|
||||
computed: {
|
||||
version () {
|
||||
|
@ -15,12 +15,12 @@ export default {
|
||||
* Set the bearer token for all future requests
|
||||
* @param {string} token The token to use to identify the user to the server
|
||||
*/
|
||||
setBearer: token => { http.defaults.headers.common['authorization'] = `Bearer ${token}` },
|
||||
setBearer: token => { http.defaults.headers.common['Authorization'] = `Bearer ${token}` },
|
||||
|
||||
/**
|
||||
* Remove the bearer token
|
||||
*/
|
||||
removeBearer: () => delete http.defaults.headers.common['authorization'],
|
||||
removeBearer: () => delete http.defaults.headers.common['Authorization'],
|
||||
|
||||
/**
|
||||
* Add a note for a prayer request
|
||||
|
@ -11,15 +11,10 @@ const webAuth = new auth0.WebAuth({
|
||||
domain: AUTH_CONFIG.domain,
|
||||
clientID: AUTH_CONFIG.clientId,
|
||||
redirectUri: AUTH_CONFIG.appDomain + AUTH_CONFIG.callbackUrl,
|
||||
audience: `https://${AUTH_CONFIG.domain}/userinfo`,
|
||||
responseType: 'token id_token',
|
||||
scope: 'openid profile email'
|
||||
})
|
||||
|
||||
const ACCESS_TOKEN = 'access_token'
|
||||
const ID_TOKEN = 'id_token'
|
||||
const EXPIRES_AT = 'expires_at'
|
||||
|
||||
class AuthService extends EventEmitter {
|
||||
|
||||
id = {
|
||||
@ -32,14 +27,10 @@ class AuthService extends EventEmitter {
|
||||
}
|
||||
profile = null
|
||||
|
||||
auth0 = new auth0.WebAuth({
|
||||
domain: AUTH_CONFIG.domain,
|
||||
clientID: AUTH_CONFIG.clientId,
|
||||
redirectUri: AUTH_CONFIG.appDomain + AUTH_CONFIG.callbackUrl,
|
||||
audience: `https://${AUTH_CONFIG.domain}/userinfo`,
|
||||
responseType: 'token id_token',
|
||||
scope: 'openid profile email'
|
||||
})
|
||||
ACCESS_TOKEN = 'access_token'
|
||||
ID_TOKEN = 'id_token'
|
||||
EXPIRES_AT = 'expires_at'
|
||||
USER_PROFILE = 'user_profile'
|
||||
|
||||
/**
|
||||
* Starts the user log in flow
|
||||
@ -55,7 +46,7 @@ class AuthService extends EventEmitter {
|
||||
*/
|
||||
parseHash () {
|
||||
return new Promise((resolve, reject) => {
|
||||
this.auth0.parseHash((err, authResult) => {
|
||||
webAuth.parseHash((err, authResult) => {
|
||||
if (err) {
|
||||
reject(err)
|
||||
} else {
|
||||
@ -65,32 +56,12 @@ class AuthService extends EventEmitter {
|
||||
})
|
||||
}
|
||||
|
||||
/**
|
||||
* Promisified userInfo function
|
||||
*
|
||||
* @param token The auth token from the login result
|
||||
*/
|
||||
userInfo (token) {
|
||||
return new Promise((resolve, reject) => {
|
||||
this.auth0.client.userInfo(token, (err, user) => {
|
||||
if (err) {
|
||||
reject(err)
|
||||
} else {
|
||||
resolve(user)
|
||||
}
|
||||
})
|
||||
})
|
||||
}
|
||||
|
||||
handleAuthentication (store) {
|
||||
this.parseHash()
|
||||
.then(authResult => {
|
||||
if (authResult && authResult.accessToken && authResult.idToken) {
|
||||
this.setSession(authResult)
|
||||
this.userInfo(authResult.accessToken)
|
||||
.then(user => {
|
||||
store.commit(mutations.USER_LOGGED_ON, user)
|
||||
})
|
||||
store.commit(mutations.USER_LOGGED_ON, this.profile)
|
||||
}
|
||||
})
|
||||
.catch(err => {
|
||||
@ -100,15 +71,16 @@ class AuthService extends EventEmitter {
|
||||
}
|
||||
|
||||
setSession (authResult) {
|
||||
this.profile = authResult.idTokenPayload
|
||||
this.id.token = authResult.idToken
|
||||
this.id.expiry = new Date(this.profile.exp * 1000);
|
||||
this.profile = authResult.idTokenPayload
|
||||
this.access.token = authResult.accessToken
|
||||
this.access.expiry = new Date(Date.now() + authResult.expiresIn * 1000)
|
||||
|
||||
localStorage.setItem(ACCESS_TOKEN, authResult.accessToken)
|
||||
localStorage.setItem(ID_TOKEN, authResult.idToken)
|
||||
localStorage.setItem(EXPIRES_AT, this.id.expiry)
|
||||
localStorage.setItem(this.ACCESS_TOKEN, authResult.accessToken)
|
||||
localStorage.setItem(this.ID_TOKEN, authResult.idToken)
|
||||
localStorage.setItem(this.EXPIRES_AT, this.id.expiry)
|
||||
localStorage.setItem(this.USER_PROFILE, JSON.stringify(this.profile))
|
||||
|
||||
this.emit('loginEvent', {
|
||||
loggedIn: true,
|
||||
@ -119,7 +91,7 @@ class AuthService extends EventEmitter {
|
||||
|
||||
renewTokens () {
|
||||
return new Promise((resolve, reject) => {
|
||||
if (localStorage.getItem(ID_TOKEN)) {
|
||||
if (localStorage.getItem(this.ID_TOKEN) !== null) {
|
||||
webAuth.checkSession({}, (err, authResult) => {
|
||||
if (err) {
|
||||
reject(err)
|
||||
@ -136,9 +108,10 @@ class AuthService extends EventEmitter {
|
||||
|
||||
logout (store, router) {
|
||||
// Clear access token and ID token from local storage
|
||||
localStorage.removeItem(ACCESS_TOKEN)
|
||||
localStorage.removeItem(ID_TOKEN)
|
||||
localStorage.removeItem(EXPIRES_AT)
|
||||
localStorage.removeItem(this.ACCESS_TOKEN)
|
||||
localStorage.removeItem(this.ID_TOKEN)
|
||||
localStorage.removeItem(this.EXPIRES_AT)
|
||||
localStorage.removeItem(this.USER_PROFILE)
|
||||
|
||||
this.idToken = null
|
||||
this.idTokenExpiry = null
|
||||
@ -154,7 +127,7 @@ class AuthService extends EventEmitter {
|
||||
}
|
||||
|
||||
isAuthenticated () {
|
||||
return Date().now() < this.id.Expiry && localStorage.getItem(ID_TOKEN)
|
||||
return Date.now() < this.id.Expiry && localStorage.getItem(this.ID_TOKEN)
|
||||
}
|
||||
|
||||
isAccessTokenValid () {
|
||||
|
@ -38,15 +38,12 @@ export default {
|
||||
return {}
|
||||
},
|
||||
computed: {
|
||||
isAuthenticated () {
|
||||
return this.$auth.isAuthenticated()
|
||||
},
|
||||
hasSnoozed () {
|
||||
return this.isAuthenticated &&
|
||||
Array.isArray(this.journal) &&
|
||||
this.journal.filter(req => req.snoozedUntil > Date.now()).length > 0
|
||||
},
|
||||
...mapState([ 'journal' ])
|
||||
...mapState([ 'isAuthenticated', 'journal' ])
|
||||
},
|
||||
methods: {
|
||||
logOn () {
|
||||
|
@ -3,6 +3,8 @@
|
||||
export default {
|
||||
/** Action to add a prayer request (pass request text) */
|
||||
ADD_REQUEST: 'add-request',
|
||||
/** Action to check if a user is authenticated, refreshing the session first if it exists */
|
||||
CHECK_AUTHENTICATION: 'check-authentication',
|
||||
/** Action to load the user's prayer journal */
|
||||
LOAD_JOURNAL: 'load-journal',
|
||||
/** Action to update a request */
|
||||
|
@ -5,7 +5,7 @@ import Vue from 'vue'
|
||||
import Vuex from 'vuex'
|
||||
|
||||
import api from '@/api'
|
||||
import AuthService from '@/auth/AuthService'
|
||||
import auth from '@/auth/AuthService'
|
||||
|
||||
import mutations from './mutation-types'
|
||||
import actions from './action-types'
|
||||
@ -13,37 +13,45 @@ import actions from './action-types'
|
||||
|
||||
Vue.use(Vuex)
|
||||
|
||||
const auth0 = new AuthService()
|
||||
|
||||
const logError = function (error) {
|
||||
if (error.response) {
|
||||
// The request was made and the server responded with a status code
|
||||
// that falls out of the range of 2xx
|
||||
console.log(error.response.data)
|
||||
console.log(error.response.status)
|
||||
console.log(error.response.headers)
|
||||
console.error(error.response.data)
|
||||
console.error(error.response.status)
|
||||
console.error(error.response.headers)
|
||||
} else if (error.request) {
|
||||
// The request was made but no response was received
|
||||
// `error.request` is an instance of XMLHttpRequest in the browser and an instance of
|
||||
// http.ClientRequest in node.js
|
||||
console.log(error.request)
|
||||
console.error(error.request)
|
||||
} else {
|
||||
// Something happened in setting up the request that triggered an Error
|
||||
console.log('Error', error.message)
|
||||
console.error('Error', error.message)
|
||||
}
|
||||
console.error(`config: ${error.config}`)
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the "Bearer" authorization header with the current access token
|
||||
*/
|
||||
const setBearer = async function () {
|
||||
try {
|
||||
await auth.getAccessToken()
|
||||
api.setBearer(localStorage.getItem(auth.ID_TOKEN))
|
||||
} catch(err) {
|
||||
if (err === 'Not logged in') {
|
||||
console.warn('API request attempted when user was not logged in')
|
||||
} else {
|
||||
console.error(err)
|
||||
}
|
||||
}
|
||||
console.log(error.config)
|
||||
}
|
||||
|
||||
export default new Vuex.Store({
|
||||
state: {
|
||||
user: JSON.parse(localStorage.getItem('user_profile') || '{}'),
|
||||
isAuthenticated: (() => {
|
||||
auth0.scheduleRenewal()
|
||||
if (auth0.isAuthenticated()) {
|
||||
api.setBearer(localStorage.getItem('id_token'))
|
||||
}
|
||||
return auth0.isAuthenticated()
|
||||
})(),
|
||||
user: JSON.parse(localStorage.getItem(auth.USER_PROFILE) || '{}'),
|
||||
isAuthenticated: auth.isAuthenticated(),
|
||||
journal: {},
|
||||
isLoadingJournal: false
|
||||
},
|
||||
@ -62,15 +70,16 @@ export default new Vuex.Store({
|
||||
if (request.lastStatus !== 'Answered') jrnl.push(request)
|
||||
state.journal = jrnl
|
||||
},
|
||||
[mutations.SET_AUTHENTICATION] (state, value) {
|
||||
state.isAuthenticated = value
|
||||
},
|
||||
[mutations.USER_LOGGED_OFF] (state) {
|
||||
state.user = {}
|
||||
api.removeBearer()
|
||||
state.isAuthenticated = false
|
||||
},
|
||||
[mutations.USER_LOGGED_ON] (state, user) {
|
||||
localStorage.setItem('user_profile', JSON.stringify(user))
|
||||
state.user = user
|
||||
api.setBearer(localStorage.getItem('id_token'))
|
||||
state.isAuthenticated = true
|
||||
}
|
||||
},
|
||||
@ -78,6 +87,7 @@ export default new Vuex.Store({
|
||||
async [actions.ADD_REQUEST] ({ commit }, { progress, requestText, recurType, recurCount }) {
|
||||
progress.$emit('show', 'indeterminate')
|
||||
try {
|
||||
await setBearer()
|
||||
const newRequest = await api.addRequest(requestText, recurType, recurCount)
|
||||
commit(mutations.REQUEST_ADDED, newRequest.data)
|
||||
progress.$emit('done')
|
||||
@ -86,11 +96,19 @@ export default new Vuex.Store({
|
||||
progress.$emit('done')
|
||||
}
|
||||
},
|
||||
async [actions.CHECK_AUTHENTICATION] ({ commit }) {
|
||||
try {
|
||||
await auth.renewTokens()
|
||||
commit(mutations.SET_AUTHENTICATION, auth.isAuthenticated())
|
||||
} catch(_) {
|
||||
commit(mutations.SET_AUTHENTICATION, false)
|
||||
}
|
||||
},
|
||||
async [actions.LOAD_JOURNAL] ({ commit }, progress) {
|
||||
commit(mutations.LOADED_JOURNAL, {})
|
||||
progress.$emit('show', 'query')
|
||||
commit(mutations.LOADING_JOURNAL, true)
|
||||
api.setBearer(localStorage.getItem('id_token'))
|
||||
await setBearer()
|
||||
try {
|
||||
const jrnl = await api.journal()
|
||||
commit(mutations.LOADED_JOURNAL, jrnl.data)
|
||||
@ -105,6 +123,7 @@ export default new Vuex.Store({
|
||||
async [actions.UPDATE_REQUEST] ({ commit, state }, { progress, requestId, status, updateText, recurType, recurCount }) {
|
||||
progress.$emit('show', 'indeterminate')
|
||||
try {
|
||||
await setBearer()
|
||||
let oldReq = (state.journal.filter(req => req.requestId === requestId) || [])[0] || {}
|
||||
if (!(status === 'Prayed' && updateText === '')) {
|
||||
if (status !== 'Answered' && (oldReq.recurType !== recurType || oldReq.recurCount !== recurCount)) {
|
||||
@ -125,6 +144,7 @@ export default new Vuex.Store({
|
||||
async [actions.SHOW_REQUEST_NOW] ({ commit }, { progress, requestId, showAfter }) {
|
||||
progress.$emit('show', 'indeterminate')
|
||||
try {
|
||||
await setBearer()
|
||||
await api.showRequest(requestId, showAfter)
|
||||
const request = await api.getRequest(requestId)
|
||||
commit(mutations.REQUEST_UPDATED, request.data)
|
||||
@ -137,6 +157,7 @@ export default new Vuex.Store({
|
||||
async [actions.SNOOZE_REQUEST] ({ commit }, { progress, requestId, until }) {
|
||||
progress.$emit('show', 'indeterminate')
|
||||
try {
|
||||
await setBearer()
|
||||
await api.snoozeRequest(requestId, until)
|
||||
const request = await api.getRequest(requestId)
|
||||
commit(mutations.REQUEST_UPDATED, request.data)
|
||||
|
@ -9,6 +9,8 @@ export default {
|
||||
REQUEST_ADDED: 'request-added',
|
||||
/** Mutation to replace a prayer request at the top of the current journal */
|
||||
REQUEST_UPDATED: 'request-updated',
|
||||
/** Mutation for setting the authentication state */
|
||||
SET_AUTHENTICATION: 'set-authentication',
|
||||
/** Mutation for logging a user off */
|
||||
USER_LOGGED_OFF: 'user-logged-off',
|
||||
/** Mutation for logging a user on (pass user) */
|
||||
|
Loading…
Reference in New Issue
Block a user