import { Action, Module, Mutation, MutationAction, VuexModule } from 'vuex-module-decorators'; import JwtDecode from 'jwt-decode'; import { LoginSubmit } from '@/models'; import api from '@/services/pm-api-client'; import { logService } from '@/services/logging'; import { userStore, measureStore } from '@/store'; const SESSION_KEY = 'session-token'; const logger = logService.getLogger('/store-modules/auth'); export interface SessionToken { iat: string; exp: number; sub: string; } @Module({ namespaced: true, name: 'auth' }) export class AuthStoreModule extends VuexModule { public authToken: string | null = null; @Action({ rawError: true }) public async login(creds: LoginSubmit): Promise { const authToken = await api.createAuthToken(creds); // API will cache this token // this should be guaranteed by the server (redirect HTTP -> HTTPS) // but we'll do a sanity check just to make sure. if (window.location.protocol === 'https:' || process.env.NODE_ENV === 'development') { // allow in dev localStorage.setItem(SESSION_KEY, authToken); } logger.trace('User login successful.'); this.context.commit('SET_TOKEN', authToken); this.loadInitialState(); return authToken; } @MutationAction({ mutate: ['authToken'], rawError: true }) public async logout() { return { authToken: null }; } @Action({ rawError: true }) public async findLocalToken(): Promise { const encodedToken = localStorage.getItem(SESSION_KEY); if (!encodedToken) { logger.trace('encodedToken was falsey'); throw new Error('Could not find an existing auth token.'); } const token = JwtDecode(encodedToken); if ((new Date(token.exp * 1000)) < new Date()) { logger.trace('token has expired: token.exp = ' + (token.exp * 1000)); throw new Error ('The existing auth token has expired.'); } api.setAuthToken(encodedToken); this.context.commit('SET_TOKEN', encodedToken); this.loadInitialState(); return encodedToken; } @Action public async loadInitialState() { userStore.fetchUser(); measureStore.fetchAllMeasures(); } @Mutation private SET_TOKEN(t: string) { logger.info('SET_TOKEN called'); this.authToken = t; } }