-
-
Save chz/f0a25fd1b12b64daaf86ef871b804fd9 to your computer and use it in GitHub Desktop.
Revisions
-
jengel3 revised this gist
Oct 30, 2020 . 1 changed file with 12 additions and 3 deletions.There are no files selected for viewing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters. Learn more about bidirectional Unicode charactersOriginal file line number Diff line number Diff line change @@ -43,7 +43,10 @@ export const mutations = { export const actions = { async login ({ commit, dispatch }, { email_address, password }) { // make an API call to login the user with an email address and password const { data: { data: { user, payload } } } = await this.$axios.post( '/api/auth/login', { email_address, password } ) // commit the user and tokens to the state commit(AUTH_MUTATIONS.SET_USER, user) @@ -52,7 +55,10 @@ export const actions = { async register ({ commit }, { email_addr, password }) { // make an API call to register the user const { data: { data: { user, payload } } } = await this.$axios.post( '/api/auth/register', { email_address, password } ) // commit the user and tokens to the state commit(AUTH_MUTATIONS.SET_USER, user) @@ -64,7 +70,10 @@ export const actions = { const { refresh_token } = state // make an API call using the refresh token to generate a new access token const { data: { data: { payload } } } = await this.$axios.post( '/api/auth/refresh', { refresh_token } ) commit(AUTH_MUTATIONS.SET_PAYLOAD, payload) }, -
jengel3 revised this gist
Oct 30, 2020 . 1 changed file with 1 addition and 0 deletions.There are no files selected for viewing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters. Learn more about bidirectional Unicode charactersOriginal file line number Diff line number Diff line change @@ -0,0 +1 @@ const { data: { ... } } = await $axios.get('/api/my-account') -
jengel3 revised this gist
Oct 30, 2020 . 1 changed file with 21 additions and 0 deletions.There are no files selected for viewing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters. Learn more about bidirectional Unicode charactersOriginal file line number Diff line number Diff line change @@ -0,0 +1,21 @@ // store/index.js // .... export const actions = { // https://nuxtjs.org/guide/vuex-store/#the-nuxtserverinit-action // automatically refresh the access token on the initial request to the server, if possible async nuxtServerInit ({ dispatch, commit, state }) { const { access_token, refresh_token } = state.auth if (access_token && refresh_token) { try { // refresh the access token await dispatch('auth/refresh') } catch (e) { // catch any errors and automatically logout the user await dispatch('auth/logout') } } }, } // ... -
jengel3 revised this gist
Oct 30, 2020 . 1 changed file with 1 addition and 0 deletions.There are no files selected for viewing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters. Learn more about bidirectional Unicode charactersOriginal file line number Diff line number Diff line change @@ -25,6 +25,7 @@ export const mutations = { [AUTH_MUTATIONS.SET_PAYLOAD] (state, { access_token, refresh_token = null }) { state.access_token = access_token // refresh token is optional, only set it if present if (refresh_token) { state.refresh_token = refresh_token } -
jengel3 renamed this gist
Oct 30, 2020 . 1 changed file with 0 additions and 0 deletions.There are no files selected for viewing
File renamed without changes. -
jengel3 revised this gist
Oct 30, 2020 . 1 changed file with 4 additions and 4 deletions.There are no files selected for viewing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters. Learn more about bidirectional Unicode charactersOriginal file line number Diff line number Diff line change @@ -1,6 +1,6 @@ { "status": "failed", "text_code": "TOKEN_EXPIRED", "message": "The JWT token is expired", "status_code": 401 } -
jengel3 revised this gist
Oct 30, 2020 . 2 changed files with 18 additions and 3 deletions.There are no files selected for viewing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters. Learn more about bidirectional Unicode charactersOriginal file line number Diff line number Diff line change @@ -0,0 +1,15 @@ // plugins/axios.js // expose the store, axios client and redirect method from the Nuxt context // https://nuxtjs.org/api/context/ export default function ({ store, app: { $axios }, redirect }) { $axios.onRequest((config) => { // check if the user is authenticated if (store.state.auth.access_token) { // set the Authorization header using the access token config.headers.Authorization = 'Bearer ' + store.state.auth.access_token } return config }) } This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters. Learn more about bidirectional Unicode charactersOriginal file line number Diff line number Diff line change @@ -1,6 +1,6 @@ { status: "failed", text_code: "TOKEN_EXPIRED", message: "The JWT token is expired", status_code: 401 } -
jengel3 revised this gist
Oct 30, 2020 . 1 changed file with 6 additions and 0 deletions.There are no files selected for viewing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters. Learn more about bidirectional Unicode charactersOriginal file line number Diff line number Diff line change @@ -0,0 +1,6 @@ { status: 'failed', text_code: 'TOKEN_EXPIRED', message: 'The JWT token is expired', status_code: 401 } -
jengel3 revised this gist
Oct 30, 2020 . 1 changed file with 87 additions and 0 deletions.There are no files selected for viewing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters. Learn more about bidirectional Unicode charactersOriginal file line number Diff line number Diff line change @@ -0,0 +1,87 @@ // plugins/axios.js // expose the store, axios client and redirect method from the Nuxt context // https://nuxtjs.org/api/context/ export default function ({ store, app: { $axios }, redirect }) { const IGNORED_PATHS = ['/auth/login', '/auth/logout', '/auth/refresh'] $axios.onRequest((config) => { // check if the user is authenticated if (store.state.auth.access_token) { // set the Authorization header using the access token config.headers.Authorization = 'Bearer ' + store.state.auth.access_token } return config }) $axios.onError((error) => { return new Promise(async (resolve, reject) => { // ignore certain paths (i.e. paths relating to authentication) const isIgnored = IGNORED_PATHS.some(path => error.config.url.includes(path)) // get the status code from the response const statusCode = error.response ? error.response.status : -1 // only handle authentication errors or errors involving the validity of the token if ((statusCode === 401 || statusCode === 422) && !isIgnored) { // API should return a reason for the error, represented here by the text_code property // Example API response: // { // status: 'failed', // text_code: 'TOKEN_EXPIRED', // message: 'The JWT token is expired', // status_code: 401 // } // retrieve the text_code property from the response, or default to null const { data: { text_code } = { text_code: null } } = error.response || {} // get the refresh token from the state if it exists const refreshToken = store.state.auth.refresh_token // determine if the error is a result of an expired access token // also ensure that the refresh token is present if (text_code === 'TOKEN_EXPIRED' && refreshToken) { // see below - consider the refresh process failed if this is a 2nd attempt at the request if (error.config.hasOwnProperty('retryAttempts')) { // immediately logout if already attempted refresh await store.dispatch('auth/logout') // redirect the user home return redirect('/') } else { // merge a new retryAttempts property into the original request config to prevent infinite-loop if refresh fails const config = { retryAttempts: 1, ...error.config } try { // attempt to refresh access token using refresh token await store.dispatch('auth/refresh') // re-run the initial request using the new request config after a successful refresh // this response will be returned to the initial calling method return resolve($axios(config)) } catch (e) { // catch any error while refreshing the token await store.dispatch('auth/logout') // redirect the user home return redirect('/') } } } else if (text_code === 'TOKEN_INVALID') { // catch any other JWT-related error (i.e. malformed token) and logout the user await store.dispatch('auth/logout') // redirect the user home return redirect('/') } } // ignore all other errors, let component or other error handlers handle them return reject(error) }) }) } -
jengel3 revised this gist
Oct 30, 2020 . 1 changed file with 4 additions and 0 deletions.There are no files selected for viewing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters. Learn more about bidirectional Unicode charactersOriginal file line number Diff line number Diff line change @@ -0,0 +1,4 @@ const email_address = '[email protected]' const password = 'abc123' await $store.dispatch('auth/login', { email_address, password }) -
jengel3 revised this gist
Oct 30, 2020 . 2 changed files with 4 additions and 0 deletions.There are no files selected for viewing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters. Learn more about bidirectional Unicode charactersOriginal file line number Diff line number Diff line change @@ -1,3 +1,5 @@ // store/auth.js // reusable aliases for mutations export const AUTH_MUTATIONS = { SET_USER: 'SET_USER', This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters. Learn more about bidirectional Unicode charactersOriginal file line number Diff line number Diff line change @@ -1,3 +1,5 @@ // plugins/local-storage.js import createPersistedState from 'vuex-persistedstate' import * as Cookies from 'js-cookie' import cookie from 'cookie' -
jengel3 revised this gist
Oct 30, 2020 . 1 changed file with 25 additions and 0 deletions.There are no files selected for viewing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters. Learn more about bidirectional Unicode charactersOriginal file line number Diff line number Diff line change @@ -0,0 +1,25 @@ import createPersistedState from 'vuex-persistedstate' import * as Cookies from 'js-cookie' import cookie from 'cookie' // access the store, http request and environment from the Nuxt context // https://nuxtjs.org/api/context/ export default ({ store, req, isDev }) => { createPersistedState({ key: 'authentication-cookie', // choose any name for your cookie paths: [ // persist the access_token and refresh_token values from the "auth" store module 'auth.access_token', 'auth.refresh_token', ], storage: { // if on the browser, parse the cookies using js-cookie otherwise parse from the raw http request getItem: key => process.client ? Cookies.getJSON(key) : cookie.parse(req.headers.cookie || '')[key], // js-cookie can handle setting both client-side and server-side cookies with one method // use isDev to determine if the cookies is accessible via https only (i.e. localhost likely won't be using https) setItem: (key, value) => Cookies.set(key, value, { expires: 14, secure: !isDev }), // also allow js-cookie to handle removing cookies removeItem: key => Cookies.remove(key) } })(store) } -
jengel3 revised this gist
Oct 30, 2020 . 1 changed file with 20 additions and 8 deletions.There are no files selected for viewing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters. Learn more about bidirectional Unicode charactersOriginal file line number Diff line number Diff line change @@ -1,22 +1,25 @@ // reusable aliases for mutations export const AUTH_MUTATIONS = { SET_USER: 'SET_USER', SET_PAYLOAD: 'SET_PAYLOAD', LOGOUT: 'LOGOUT', } export const state = () => ({ access_token: null, // JWT access token refresh_token: null, // JWT refresh token id: null, // user id email_address: null, // user email address }) export const mutations = { // store the logged in user in the state [AUTH_MUTATIONS.SET_USER] (state, { id, email_address }) { state.id = id state.email_address = email_address }, // store new or updated token fields in the state [AUTH_MUTATIONS.SET_PAYLOAD] (state, { access_token, refresh_token = null }) { state.access_token = access_token @@ -25,6 +28,7 @@ export const mutations = { } }, // clear our the state, essentially logging out the user [AUTH_MUTATIONS.LOGOUT] (state) { state.id = null state.email_address = null @@ -35,33 +39,41 @@ export const mutations = { export const actions = { async login ({ commit, dispatch }, { email_address, password }) { // make an API call to login the user with an email address and password const { data: { data: { user, payload } } } = await this.$axios.post('/api/auth/login', { email_address, password }) // commit the user and tokens to the state commit(AUTH_MUTATIONS.SET_USER, user) commit(AUTH_MUTATIONS.SET_PAYLOAD, payload) }, async register ({ commit }, { email_addr, password }) { // make an API call to register the user const { data: { data: { user, payload } } } = await this.$axios.post('/api/auth/register', { email_address, password }) // commit the user and tokens to the state commit(AUTH_MUTATIONS.SET_USER, user) commit(AUTH_MUTATIONS.SET_PAYLOAD, payload) }, // given the current refresh token, refresh the user's access token to prevent expiry async refresh ({ commit, state }) { const { refresh_token } = state // make an API call using the refresh token to generate a new access token const { data: { data: { payload } } } = await this.$axios.post('/api/auth/refresh', { refresh_token }) commit(AUTH_MUTATIONS.SET_PAYLOAD, payload) }, // logout the user logout ({ commit, state }) { commit(AUTH_MUTATIONS.LOGOUT) }, } export const getters = { // determine if the user is authenticated based on the presence of the access token isAuthenticated: (state) => { return state.access_token && state.access_token !== '' }, -
jengel3 created this gist
Oct 30, 2020 .There are no files selected for viewing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters. Learn more about bidirectional Unicode charactersOriginal file line number Diff line number Diff line change @@ -0,0 +1,68 @@ export const AUTH_MUTATIONS = { SET_USER: 'SET_USER', SET_PAYLOAD: 'SET_PAYLOAD', LOGOUT: 'LOGOUT', } export const state = () => ({ access_token: null, refresh_token: null, id: null, email_address: null, }) export const mutations = { [AUTH_MUTATIONS.SET_USER] (state, { id, email_address, first_name, last_name }) { state.id = id state.email_address = email_address }, [AUTH_MUTATIONS.SET_PAYLOAD] (state, { access_token, refresh_token = null }) { state.access_token = access_token if (refresh_token) { state.refresh_token = refresh_token } }, [AUTH_MUTATIONS.LOGOUT] (state) { state.id = null state.email_address = null state.access_token = null state.refresh_token = null }, } export const actions = { async login ({ commit, dispatch }, { email_address, password }) { const { data: { data: { user, payload } } } = await this.$api.users.login(email_address, password) commit(AUTH_MUTATIONS.SET_USER, user) commit(AUTH_MUTATIONS.SET_PAYLOAD, payload) }, async register ({ commit }, { email_addr, password }) { const { data: { data: { user, payload } } } = await this.$api.users.register(email_address, password) commit(AUTH_MUTATIONS.SET_USER, user) commit(AUTH_MUTATIONS.SET_PAYLOAD, payload) }, async refresh ({ commit, state }) { const { refresh_token } = state const { data: { data: { payload } } } = await this.$api.users.refresh(refresh_token) commit(AUTH_MUTATIONS.SET_PAYLOAD, payload) }, logout ({ commit, state }) { commit(AUTH_MUTATIONS.LOGOUT) }, } export const getters = { isAuthenticated: (state) => { return state.access_token && state.access_token !== '' }, }