diff --git a/frontend/src/components/AutoLogout.vue b/frontend/src/components/AutoLogout.vue
index 3c29cf12caafb3c05f6213771a7f1543fccf08c5..b7677ee1773e5114bb0435f7fff7ae4dd0868414 100644
--- a/frontend/src/components/AutoLogout.vue
+++ b/frontend/src/components/AutoLogout.vue
@@ -28,6 +28,8 @@
 
 <script>
 import {mapState} from 'vuex'
+import {Authentication} from '@/store/modules/authentication'
+import {actions} from '@/store/actions'
 
 export default {
   name: 'auto-logout',
@@ -41,19 +43,17 @@ export default {
     ...mapState([
       'lastAppInteraction'
     ]),
-    ...mapState({
-      lastTokenRefreshTry: state => state.authentication.lastTokenRefreshTry,
-      refreshingToken: state => state.authentication.refreshingToken,
-      jwtTimeDelta: state => state.authentication.jwtTimeDelta
-    })
+    lastTokenRefreshTry () { return Authentication.state.lastTokenRefreshTry },
+    refreshingToken () { return Authentication.state.refreshingToken },
+    jwtTimeDelta () { return Authentication.state.jwtTimeDelta }
   },
   methods: {
     logout () {
       this.logoutDialog = false
-      this.$store.dispatch('logout')
+      actions.logout()
     },
     continueWork () {
-      this.$store.dispatch('refreshJWT')
+      Authentication.refreshJWT()
       this.logoutDialog = false
     }
   },
@@ -64,7 +64,7 @@ export default {
       // refresh jwt if it's older than 20% of his maximum age
       if (this.$route.name !== 'login' && timeSinceLastRefresh > timeDelta * 0.2 &&
           !this.refreshingToken) {
-        this.$store.dispatch('refreshJWT')
+        Authentication.refreshJWT()
       }
     }
   },
@@ -75,7 +75,7 @@ export default {
       if (this.$route.name !== 'login' && this.$store.getters.isLoggedIn) {
         if (Date.now() > this.lastTokenRefreshTry + this.jwtTimeDelta) {
           this.logoutDialog = false
-          this.$store.dispatch('logout', "You've been logged out due to inactivity.")
+          actions.logout("You've been logged out due to inactivity.")
         } else if (Date.now() + timeToLogOutDialog > this.lastTokenRefreshTry + this.jwtTimeDelta) {
           this.logoutDialog = true
         }
diff --git a/frontend/src/components/BaseLayout.vue b/frontend/src/components/BaseLayout.vue
index b02083b3b0c8423a6270fc8309d920fff25d4cc6..db4e169c438d857c22f8e972251ce9f5b21e1a14 100644
--- a/frontend/src/components/BaseLayout.vue
+++ b/frontend/src/components/BaseLayout.vue
@@ -88,18 +88,15 @@ import { mapGetters, mapState } from 'vuex'
 import {UI} from '@/store/modules/ui'
 import { mapStateToComputedGetterSetter } from '@/util/helpers'
 import UserOptions from '@/components/UserOptions'
+import {Authentication} from '@/store/modules/authentication'
 
 export default {
   name: 'base-layout',
   components: {UserOptions},
   computed: {
-    ...mapGetters([
-      'gradySpeak'
-    ]),
-    ...mapState({
-      username: state => state.authentication.user.username,
-      userRole: state => state.authentication.user.role
-    }),
+    username () { return Authentication.state.user.username },
+    userRole () { return Authentication.state.user.role },
+    gradySpeak () { return Authentication.gradySpeak },
     ...mapStateToComputedGetterSetter({
       pathPrefix: 'UI',
       items: [
diff --git a/frontend/src/components/CorrectionStatistics.vue b/frontend/src/components/CorrectionStatistics.vue
index a3bf9eadecab5a7c89bedf730633fc090fc11023..ecd499f279ae6eac1a06a137185fa8e46d2b58db 100644
--- a/frontend/src/components/CorrectionStatistics.vue
+++ b/frontend/src/components/CorrectionStatistics.vue
@@ -32,6 +32,8 @@
 </template>
 
 <script>
+import { actions } from '@/store/actions'
+
 export default {
   name: 'correction-statistics',
   data () {
@@ -45,7 +47,7 @@ export default {
     }
   },
   created () {
-    this.$store.dispatch('getStatistics').then(() => { this.loaded = true })
+    actions.getStatistics().then(() => { this.loaded = true })
   }
 }
 </script>
diff --git a/frontend/src/components/PasswordChangeDialog.vue b/frontend/src/components/PasswordChangeDialog.vue
index 03e4758ad3a960ec56961a18869d16d2749fb6cf..8ddc07bcbc365295699e6f720dec7308b058d6f1 100644
--- a/frontend/src/components/PasswordChangeDialog.vue
+++ b/frontend/src/components/PasswordChangeDialog.vue
@@ -37,6 +37,7 @@
 <script>
 import {mapState} from 'vuex'
 import { changePassword } from '@/api'
+import { Authentication } from '@/store/modules/authentication'
 
 export default {
   name: 'PasswordChangeDialog',
@@ -49,9 +50,7 @@ export default {
     }
   },
   computed: {
-    ...mapState({
-      userPk: state => state.authentication.user.pk
-    }),
+    userPk () { return Authentication.state.user.pk },
     equalNewPasswords () {
       return this.newPassword === this.newPasswordRepeated
     },
diff --git a/frontend/src/components/UserOptions.vue b/frontend/src/components/UserOptions.vue
index 96fffc4c4be56e513700bd219e5cf78951547d6f..5f6677bee0c882b977553382928a679c1bd74f82 100644
--- a/frontend/src/components/UserOptions.vue
+++ b/frontend/src/components/UserOptions.vue
@@ -17,6 +17,7 @@
 
 <script>
 import PasswordChangeDialog from '@/components/PasswordChangeDialog'
+import {Authentication} from '@/store/modules/authentication'
 export default {
   name: 'UserOptions',
   components: {PasswordChangeDialog},
@@ -27,7 +28,7 @@ export default {
         {
           display: 'Change password',
           action: () => { this.displayComponent = PasswordChangeDialog },
-          condition: () => !this.$store.getters.isStudent
+          condition: () => !Authentication.isStudent
         }
       ]
     }
diff --git a/frontend/src/components/feedback_list/FeedbackSearchOptions.vue b/frontend/src/components/feedback_list/FeedbackSearchOptions.vue
index c2db7e9c529c990e16bb92ba81146698dd817c94..3eb5514e6d0ccf8ff8019a8cc4289f8089d3182a 100644
--- a/frontend/src/components/feedback_list/FeedbackSearchOptions.vue
+++ b/frontend/src/components/feedback_list/FeedbackSearchOptions.vue
@@ -64,6 +64,7 @@
 import {mapState, mapGetters} from 'vuex'
 import {namespace, feedbackSearchOptsMut} from '@/store/modules/feedback_list/feedback-search-options'
 import {mapStateToComputedGetterSetter} from '@/util/helpers'
+import {Authentication} from '@/store/modules/authentication'
 
 export default {
   name: 'feedback-search-options',
@@ -76,9 +77,7 @@ export default {
     ...mapState([
       'tutors'
     ]),
-    ...mapGetters([
-      'isReviewer'
-    ]),
+    isReviewer () { return Authentication.isReviewer },
     tutorNames () {
       return this.tutors.map(tutor => tutor.username)
     },
diff --git a/frontend/src/components/submission_notes/SubmissionCorrection.vue b/frontend/src/components/submission_notes/SubmissionCorrection.vue
index a23d41110e15d588b49a25b7366d9fac09fa9a54..5339159c8724371c92cb58fbe859c3571c37f766 100644
--- a/frontend/src/components/submission_notes/SubmissionCorrection.vue
+++ b/frontend/src/components/submission_notes/SubmissionCorrection.vue
@@ -65,6 +65,7 @@ import BaseAnnotatedSubmission from '@/components/submission_notes/base/BaseAnno
 import SubmissionLine from '@/components/submission_notes/base/SubmissionLine'
 import {subNotesMut, subNotesNamespace} from '@/store/modules/submission-notes'
 import RouteChangeConfirmation from '@/components/submission_notes/RouteChangeConfirmation'
+import {Authentication} from '@/store/modules/authentication'
 
 export default {
   components: {
@@ -96,7 +97,6 @@ export default {
   },
   computed: {
     ...mapState({
-      user: state => state.authentication.user.username,
       showEditorOnLine: state => state.submissionNotes.ui.showEditorOnLine,
       selectedComment: state => state.submissionNotes.ui.selectedCommentOnLine,
       origFeedback: state => state.submissionNotes.origFeedback.feedbackLines,
@@ -104,11 +104,12 @@ export default {
       showFeedback: state => state.submissionNotes.ui.showFeedback
     }),
     ...mapGetters([
-      'isStudent',
-      'isTutor',
-      'isReviewer',
       'workInProgress'
     ]),
+    isStudent () { return Authentication.isStudent },
+    isTutor () { return Authentication.isTutor },
+    isReviewer () { return Authentication.isReviewer },
+    user () { return Authentication.state.user.username },
     submission () {
       return this.$store.getters['submissionNotes/submission']
     },
diff --git a/frontend/src/components/submission_notes/toolbars/AnnotatedSubmissionBottomToolbar.vue b/frontend/src/components/submission_notes/toolbars/AnnotatedSubmissionBottomToolbar.vue
index c26aea454c0cb479e4b3f5bff2f4ee1d531fdf68..49c9af1b22a15a7592bc8970e770fb6f43946da3 100644
--- a/frontend/src/components/submission_notes/toolbars/AnnotatedSubmissionBottomToolbar.vue
+++ b/frontend/src/components/submission_notes/toolbars/AnnotatedSubmissionBottomToolbar.vue
@@ -55,6 +55,7 @@
 
 <script>
 import {subNotesMut, subNotesNamespace} from '@/store/modules/submission-notes'
+import {Authentication} from '@/store/modules/authentication'
 
 export default {
   name: 'annotated-submission-bottom-toolbar',
@@ -92,7 +93,7 @@ export default {
       }
     },
     showFinalCheckbox () {
-      return !this.$store.getters['submissionNotes/isFeedbackCreation'] || this.$store.getters.isReviewer
+      return !this.$store.getters['submissionNotes/isFeedbackCreation'] || Authentication.isReviewer
     }
   },
   watch: {
@@ -106,12 +107,12 @@ export default {
   methods: {
     initialFinalStatus () {
       if (this.$route.name === 'subscription') {
-        return !this.$store.getters['submissionNotes/isFeedbackCreation'] || this.$store.getters.isReviewer
+        return !this.$store.getters['submissionNotes/isFeedbackCreation'] || Authentication.isReviewer
       } else {
         if (this.feedback.hasOwnProperty('isFinal')) {
           return this.feedback.isFinal
         } else {
-          return !this.$store.getters['submissionNotes/isFeedbackCreation'] || this.$store.getters.isReviewer
+          return !this.$store.getters['submissionNotes/isFeedbackCreation'] || Authentication.isReviewer
         }
       }
     },
diff --git a/frontend/src/components/subscriptions/SubscriptionCreation.vue b/frontend/src/components/subscriptions/SubscriptionCreation.vue
index 8dabfedd401bc82bbe7dc9164a6f32a2510acfeb..e41d00abfa0c3e454596ed6cc27c4dd300e126fa 100644
--- a/frontend/src/components/subscriptions/SubscriptionCreation.vue
+++ b/frontend/src/components/subscriptions/SubscriptionCreation.vue
@@ -29,6 +29,8 @@
 </template>
 
 <script>
+import {Authentication} from '@/store/modules/authentication'
+
 const stages = [
   {
     text: 'Initial Feedback',
@@ -68,7 +70,7 @@ export default {
   computed: {
     possibleStages () {
       let possibleStages = [...stages]
-      if (this.$store.getters.isReviewer) {
+      if (Authentication.isReviewer) {
         possibleStages.push({
           text: 'Conflict resolution',
           stage: 'feedback-conflict-resolution'
diff --git a/frontend/src/components/subscriptions/SubscriptionList.vue b/frontend/src/components/subscriptions/SubscriptionList.vue
index d62b05a93266d1e036fc6646cfda881966ff1aa1..c31e578caf276d06924d5792d2ee6c28b00ec41c 100644
--- a/frontend/src/components/subscriptions/SubscriptionList.vue
+++ b/frontend/src/components/subscriptions/SubscriptionList.vue
@@ -30,6 +30,7 @@
 <script>
 import {mapGetters, mapActions, mapState} from 'vuex'
 import {UI} from '@/store/modules/ui'
+import {actions} from '@/store/actions'
 import SubscriptionCreation from '@/components/subscriptions/SubscriptionCreation'
 import SubscriptionForList from '@/components/subscriptions/SubscriptionForList'
 import SubscriptionsForStage from '@/components/subscriptions/SubscriptionsForStage'
@@ -64,9 +65,7 @@ export default {
   },
   methods: {
     ...mapActions([
-      'updateSubmissionTypes',
       'getCurrentAssignment',
-      'getExamTypes',
       'subscribeToAll',
       'cleanAssignmentsFromSubscriptions'
     ]),
@@ -78,7 +77,7 @@ export default {
     }
   },
   created () {
-    const typesAndSubscriptions = [this.updateSubmissionTypes(), this.getSubscriptions()]
+    const typesAndSubscriptions = [actions.updateSubmissionTypes(), this.getSubscriptions()]
     Promise.all(typesAndSubscriptions).then(() => {
       this.subscribeToAll()
       this.cleanAssignmentsFromSubscriptions()
diff --git a/frontend/src/main.ts b/frontend/src/main.ts
index ad81436ec767936f2e0d2118a82e08287f7d99f8..774733cd7bf8ebf172f899b8a9b817ad3ad845ae 100644
--- a/frontend/src/main.ts
+++ b/frontend/src/main.ts
@@ -1,7 +1,7 @@
 import Vue from 'vue'
+import store from './store/store'
 import App from './App.vue'
 import router from './router/index'
-import store from './store/store'
 import Vuetify from 'vuetify'
 import Notifications from 'vue-notification'
 import Clipboard from 'v-clipboard'
diff --git a/frontend/src/pages/LayoutSelector.vue b/frontend/src/pages/LayoutSelector.vue
index 5175019934de88b1907137ac19c6989e4958c9c9..8303d03618859101ee067aa859cdf82f6f1766be 100644
--- a/frontend/src/pages/LayoutSelector.vue
+++ b/frontend/src/pages/LayoutSelector.vue
@@ -12,6 +12,7 @@ import {mapGetters} from 'vuex'
 import TutorLayout from '@/pages/tutor/TutorLayout'
 import StudentLayout from '@/pages/student/StudentLayout'
 import ReviewerLayout from '@/pages/reviewer/ReviewerLayout'
+import {Authentication} from '@/store/modules/authentication'
 
 export default {
   components: {
@@ -20,11 +21,9 @@ export default {
     TutorLayout},
   name: 'layout-selector',
   computed: {
-    ...mapGetters([
-      'isStudent',
-      'isTutor',
-      'isReviewer'
-    ]),
+    isStudent () { return Authentication.isStudent },
+    isTutor () { return Authentication.isTutor },
+    isReviewer () { return Authentication.isReviewer },
     layout () {
       if (this.isStudent) {
         return 'student-layout'
diff --git a/frontend/src/pages/Login.vue b/frontend/src/pages/Login.vue
index 0988645e495fe611959f06788d662156c367236b..f73e92788ecaeb1a146f3b5e1214357758b2ea89 100644
--- a/frontend/src/pages/Login.vue
+++ b/frontend/src/pages/Login.vue
@@ -41,7 +41,7 @@
 <script>
 import {mapActions, mapState} from 'vuex'
 import RegisterDialog from '@/components/RegisterDialog'
-import { authMut } from '@/store/modules/authentication'
+import {Authentication as Auth} from '@/store/modules/authentication'
 
 export default {
   components: {RegisterDialog},
@@ -57,10 +57,8 @@ export default {
     }
   },
   computed: {
-    ...mapState({
-      msg: state => state.authentication.message,
-      userRole: state => state.authentication.user.role
-    }),
+    msg () { return Auth.state.message },
+    userRole () { return Auth.state.user.role },
     production () {
       return process.env.NODE_ENV === 'production'
     },
@@ -69,18 +67,13 @@ export default {
     }
   },
   methods: {
-    ...mapActions([
-      'getJWT',
-      'getUser',
-      'getJWTTimeDelta'
-    ]),
     submit () {
       this.loading = true
-      this.getJWT(this.credentials).then(() => {
-        this.getUser().then(() => {
+      Auth.getJWT(this.credentials).then(() => {
+        Auth.getUser().then(() => {
           this.$router.push({name: 'home'})
         })
-        this.getJWTTimeDelta()
+        Auth.getJWTTimeDelta()
         this.loading = false
       }).catch(() => { this.loading = false })
     },
@@ -88,7 +81,7 @@ export default {
       this.registerDialog = false
       this.credentials.username = credentials.username
       this.credentials.password = credentials.password
-      this.$store.commit(authMut.SET_MESSAGE, 'Your account is being activated. Please wait.')
+      Auth.SET_MESSAGE('Your account is being activated. Please wait.')
     }
   }
 }
diff --git a/frontend/src/pages/StartPageSelector.vue b/frontend/src/pages/StartPageSelector.vue
index 97a06a4436ff9fb0e89a1d1487be1bdf06503bc7..35bceedd41bca637a3d268dcc05491ed25abdbb8 100644
--- a/frontend/src/pages/StartPageSelector.vue
+++ b/frontend/src/pages/StartPageSelector.vue
@@ -8,6 +8,7 @@ import {mapGetters} from 'vuex'
 import TutorStartPage from '@/pages/tutor/TutorStartPage'
 import StudentPage from '@/pages/student/StudentPage'
 import ReviewerStartPage from '@/pages/reviewer/ReviewerStartPage'
+import {Authentication} from '@/store/modules/authentication'
 export default {
   name: 'start-page-selector',
   components: {
@@ -16,11 +17,9 @@ export default {
     TutorStartPage
   },
   computed: {
-    ...mapGetters([
-      'isStudent',
-      'isTutor',
-      'isReviewer'
-    ]),
+    isStudent () { return Authentication.isStudent },
+    isTutor () { return Authentication.isTutor },
+    isReviewer () { return Authentication.isReviewer },
     startPage () {
       if (this.isStudent) {
         return 'student-page'
diff --git a/frontend/src/router/index.ts b/frontend/src/router/index.ts
index 25b1aeee5b8f2fa7288587de7e8c2e923231c0d9..d2d70bfc5d459d84bc0a96ade6964c0c44e041c6 100644
--- a/frontend/src/router/index.ts
+++ b/frontend/src/router/index.ts
@@ -15,7 +15,7 @@ import FeedbackHistoryPage from '@/pages/base/FeedbackHistoryPage.vue'
 import FeedbackTable from '@/components/feedback_list/FeedbackTable.vue'
 import FeedbackListHelpCard from '@/components/feedback_list/FeedbackListHelpCard.vue'
 import VueInstance from '@/main'
-import store from '@/store/store'
+import {Authentication} from '@/store/modules/authentication'
 
 Vue.use(Router)
 
@@ -31,7 +31,7 @@ function denyAccess (next: rerouteFunc, redirect: Route) {
 }
 
 let tutorOrReviewerOnly: NavigationGuard = function (to, from, next) {
-  if (store.getters.isTutorOrReviewer) {
+  if (Authentication.isTutorOrReviewer) {
     next()
   } else {
     denyAccess(next, from)
@@ -39,7 +39,7 @@ let tutorOrReviewerOnly: NavigationGuard = function (to, from, next) {
 }
 
 let reviewerOnly: NavigationGuard = function (to, from, next) {
-  if (store.getters.isReviewer) {
+  if (Authentication.isReviewer) {
     next()
   } else {
     denyAccess(next, from)
@@ -47,7 +47,7 @@ let reviewerOnly: NavigationGuard = function (to, from, next) {
 }
 
 let studentOnly: NavigationGuard = function (to, from, next) {
-  if (store.getters.isStudent) {
+  if (Authentication.isStudent) {
     next()
   } else {
     next(false)
@@ -55,7 +55,7 @@ let studentOnly: NavigationGuard = function (to, from, next) {
 }
 
 let checkLoggedIn: NavigationGuard = function (to, from, next) {
-  if (store.getters.isLoggedIn) {
+  if (Authentication.isLoggedIn) {
     next()
   } else {
     next('/login/')
diff --git a/frontend/src/store/actions.ts b/frontend/src/store/actions.ts
index e1fecc60798cc1beac4bfc2cd97177db4d0fa6d6..14a5889c9ef6c164f64daff137c9b28b4fa84126 100644
--- a/frontend/src/store/actions.ts
+++ b/frontend/src/store/actions.ts
@@ -2,7 +2,7 @@ import { ActionContext } from "vuex";
 import { BareActionContext, getStoreBuilder } from "vuex-typex";
 
 import { mutations as mut } from "./mutations";
-import { authMut } from "@/store/modules/authentication";
+import { Authentication } from "@/store/modules/authentication";
 import { subNotesMut } from "@/store/modules/submission-notes";
 import * as api from "@/api";
 import router from "@/router/index";
@@ -77,14 +77,14 @@ function logout(
   const { commit, getters, state } = <ActionContext<RootState, RootState>>(
     context
   );
-  if (getters.isStudent) {
+  if (Authentication.isStudent) {
     // change active to false when user logs out
     // TODO this should belong in auth module
-    api.changeActiveForUser((state as any).authentication.user.pk, false);
+    api.changeActiveForUser(Authentication.state.user.pk, false);
   }
   mut.RESET_STATE();
   commit("submissionNotes/" + subNotesMut.RESET_STATE);
-  commit(authMut.SET_MESSAGE, message);
+  Authentication.SET_MESSAGE(message);
   router.push({ name: "login" });
   router.go(0);
 }
@@ -92,8 +92,8 @@ function logout(
 const mb = getStoreBuilder<RootState>();
 
 export const actions = {
-  updateSubmissionTypes: mb.dispatch(getExamTypes),
-  getExamTypes: mb.dispatch(updateSubmissionTypes),
+  updateSubmissionTypes: mb.dispatch(updateSubmissionTypes),
+  getExamTypes: mb.dispatch(getExamTypes),
   getStudents: mb.dispatch(getStudents),
   getTutors: mb.dispatch(getTutors),
   getFeedback: mb.dispatch(getFeedback),
diff --git a/frontend/src/store/getters.ts b/frontend/src/store/getters.ts
index 6d4aafded1ef2b08b0cb013ea40397db819499bd..09fbeafeeba820fa536af933771258a13e6292f6 100644
--- a/frontend/src/store/getters.ts
+++ b/frontend/src/store/getters.ts
@@ -3,6 +3,8 @@ import {getStoreBuilder} from 'vuex-typex'
 
 const mb = getStoreBuilder<RootState>()
 
+const stateGetter = mb.state()
+
 const correctedGetter = mb.read(function corrected (state) {
   return state.statistics.submissionTypeProgress.every(progress => {
     return progress.feedbackFinal === progress.submissionCount
@@ -20,6 +22,7 @@ const submissionTypeGetter = mb.read(function submissionType (state) {
 })
 
 export const getters = {
+  get state () { return stateGetter() },
   get corrected () { return correctedGetter() },
   get submission () { return submissionGetter() },
   get submissionType () { return submissionTypeGetter() }
diff --git a/frontend/src/store/modules/authentication.ts b/frontend/src/store/modules/authentication.ts
index 34cb5c88c9a5c35ccc167b93268ca4dfb013b17a..79e330d98b05d655381808a6214ce3dec4426779 100644
--- a/frontend/src/store/modules/authentication.ts
+++ b/frontend/src/store/modules/authentication.ts
@@ -1,14 +1,15 @@
 import * as api from '@/api'
 import gradySays from '../grady_speak'
-import {ActionContext, Module} from 'vuex'
+import {BareActionContext, getStoreBuilder} from 'vuex-typex'
 import {UserAccount} from '@/models'
+import {RootState} from '@/store/store'
 
 export interface Credentials {
     username: string,
     password: string
 }
 
-interface AuthState {
+export interface AuthState {
     token: string,
     lastTokenRefreshTry: number,
     refreshingToken: boolean,
@@ -31,109 +32,119 @@ function initialState (): AuthState {
   }
 }
 
-export const authMut = Object.freeze({
-  SET_MESSAGE: 'SET_MESSAGE',
-  SET_JWT_TOKEN: 'SET_JWT_TOKEN',
-  SET_JWT_TIME_DELTA: 'SET_JWT_TIME_DELTA',
-  SET_USER: 'SET_USER',
-  SET_LAST_TOKEN_REFRESH_TRY: 'SET_LAST_TOKEN_REFRESH_TRY',
-  RESET_STATE: 'RESET_STATE',
-  SET_REFRESHING_TOKEN: 'SET_REFRESHING_TOKEN'
+const mb = getStoreBuilder<RootState>().module('Authentication', initialState())
+
+const stateGetter = mb.state()
+
+const gradySpeakGetter = mb.read(function gradySpeak () {
+  return gradySays[Math.floor(Math.random() * gradySays.length)]
+})
+const isStudentGetter = mb.read(function isStudent (state: AuthState) {
+  return state.user.role === UserAccount.RoleEnum.Student
+})
+const isTutorGetter = mb.read(function isTutor (state: AuthState) {
+  return state.user.role === UserAccount.RoleEnum.Tutor
+})
+const isReviewerGetter = mb.read(function isReviewer (state: AuthState) {
+  return state.user.role === UserAccount.RoleEnum.Reviewer
+})
+const isTutorOrReviewerGetter = mb.read(function isTutorOrReviewer (state: AuthState, getters) {
+  return getters.isTutor || getters.isReviewer
+})
+const isLoggedInGetter = mb.read(function isLoggedIn (state: AuthState) {
+  return !!state.token
 })
 
-const authentication: Module<AuthState, any> = {
-  state: initialState(),
-  getters: {
-    gradySpeak: () => {
-      return gradySays[Math.floor(Math.random() * gradySays.length)]
-    },
-    isStudent: (state: AuthState) => {
-      return state.user.role === UserAccount.RoleEnum.Student
-    },
-    isTutor: (state: AuthState) => {
-      return state.user.role === UserAccount.RoleEnum.Tutor
-    },
-    isReviewer: (state: AuthState) => {
-      return state.user.role === UserAccount.RoleEnum.Reviewer
-    },
-    isTutorOrReviewer: (state: AuthState, getters) => {
-      return getters.isTutor || getters.isReviewer
-    },
-    isLoggedIn: (state: AuthState) => !!state.token
-  },
-  mutations: {
-    [authMut.SET_MESSAGE] (state: AuthState, message: string) {
-      state.message = message
-    },
-    [authMut.SET_JWT_TOKEN] (state: AuthState, token: string) {
-      sessionStorage.setItem('token', token)
-      state.token = token
-    },
-    [authMut.SET_JWT_TIME_DELTA] (state: AuthState, timeDelta: number) {
-      state.jwtTimeDelta = timeDelta
-    },
-    [authMut.SET_USER] (state: AuthState, user) {
-      state.user = user
-    },
-    [authMut.SET_REFRESHING_TOKEN] (state: AuthState, refreshing: boolean) {
-      state.refreshingToken = refreshing
-    },
-    [authMut.SET_LAST_TOKEN_REFRESH_TRY] (state: AuthState) {
-      state.lastTokenRefreshTry = Date.now()
-    },
-    [authMut.RESET_STATE] (state: AuthState) {
-      sessionStorage.setItem('token', '')
-      Object.assign(state, initialState())
-    }
-  },
-  actions: {
-    async getJWT (context: ActionContext<AuthState, any>, credentials: Credentials) {
-      try {
-        const token = await api.fetchJWT(credentials)
-        context.commit(authMut.SET_JWT_TOKEN, token.token)
-      } catch (error) {
-        let errorMsg
-        if (!error.response) {
-          errorMsg = 'Cannot reach server.'
-        } else if (error.response.status === 400) {
-          errorMsg = 'Unable to log in with provided credentials.'
-        } else if (error.response.status === 429) {
-          errorMsg = error.response.data.detail
-        }
-        context.commit(authMut.SET_MESSAGE, errorMsg)
-        throw errorMsg
-      } finally {
-        context.commit(authMut.SET_LAST_TOKEN_REFRESH_TRY)
-      }
-    },
-    async refreshJWT ({state, commit}) {
-      commit(authMut.SET_REFRESHING_TOKEN, true)
-      try {
-        const token = await api.refreshJWT(state.token)
-        commit(authMut.SET_JWT_TOKEN, token.token)
-      } finally {
-        commit(authMut.SET_REFRESHING_TOKEN, false)
-        commit(authMut.SET_LAST_TOKEN_REFRESH_TRY)
-      }
-    },
-    async getUser ({commit}) {
-      try {
-        const user = await api.getOwnUser()
-        commit(authMut.SET_USER, user)
-      } catch (err) {
-        commit(authMut.SET_MESSAGE, 'Unable to fetch user.')
-      }
-    },
-    async getJWTTimeDelta ({commit}) {
-      try {
-        const delta = await api.fetchJWTTimeDelta()
-        // multiply by 1000 to convert to ms
-        commit(authMut.SET_JWT_TIME_DELTA, delta * 1000)
-      } catch (err) {
-        console.log(err)
-      }
+function SET_MESSAGE (state: AuthState, message: string) {
+  state.message = message
+}
+function SET_JWT_TOKEN (state: AuthState, token: string) {
+  sessionStorage.setItem('token', token)
+  state.token = token
+}
+function SET_JWT_TIME_DELTA (state: AuthState, timeDelta: number) {
+  state.jwtTimeDelta = timeDelta
+}
+function SET_USER (state: AuthState, user: UserAccount) {
+  state.user = user
+}
+function SET_REFRESHING_TOKEN (state: AuthState, refreshing: boolean) {
+  state.refreshingToken = refreshing
+}
+function SET_LAST_TOKEN_REFRESH_TRY (state: AuthState) {
+  state.lastTokenRefreshTry = Date.now()
+}
+function RESET_STATE (state: AuthState) {
+  sessionStorage.setItem('token', '')
+  Object.assign(state, initialState())
+}
+
+async function getJWT (context: BareActionContext<AuthState, RootState>, credentials: Credentials) {
+  try {
+    const token = await api.fetchJWT(credentials)
+    Authentication.SET_JWT_TOKEN(token.token)
+  } catch (error) {
+    let errorMsg
+    if (!error.response) {
+      errorMsg = 'Cannot reach server.'
+    } else if (error.response.status === 400) {
+      errorMsg = 'Unable to log in with provided credentials.'
+    } else if (error.response.status === 429) {
+      errorMsg = error.response.data.detail
     }
+    Authentication.SET_MESSAGE(errorMsg)
+    throw errorMsg
+  } finally {
+    Authentication.SET_LAST_TOKEN_REFRESH_TRY()
+  }
+}
+async function refreshJWT ({state}: BareActionContext<AuthState, RootState>) {
+  Authentication.SET_REFRESHING_TOKEN(true)
+  try {
+    const token = await api.refreshJWT(state.token)
+    Authentication.SET_JWT_TOKEN(token.token)
+  } finally {
+    Authentication.SET_REFRESHING_TOKEN(false)
+    Authentication.SET_LAST_TOKEN_REFRESH_TRY()
+  }
+}
+async function getUser () {
+  try {
+    const user = await api.getOwnUser()
+    Authentication.SET_USER(user)
+  } catch (err) {
+    Authentication.SET_MESSAGE('Unable to fetch user.')
+  }
+}
+async function getJWTTimeDelta () {
+  try {
+    const delta = await api.fetchJWTTimeDelta()
+    // multiply by 1000 to convert to ms
+    Authentication.SET_JWT_TIME_DELTA(delta * 1000)
+  } catch (err) {
+    console.log(err)
   }
 }
 
-export default authentication
+export const Authentication = {
+  get state () { return stateGetter() },
+  get gradySpeak () { return gradySpeakGetter() },
+  get isStudent () { return isStudentGetter() },
+  get isTutor () { return isTutorGetter() },
+  get isReviewer () { return isReviewerGetter() },
+  get isTutorOrReviewer () { return isTutorOrReviewerGetter() },
+  get isLoggedIn () { return isLoggedInGetter() },
+
+  SET_MESSAGE: mb.commit(SET_MESSAGE),
+  SET_JWT_TOKEN: mb.commit(SET_JWT_TOKEN),
+  SET_JWT_TIME_DELTA: mb.commit(SET_JWT_TIME_DELTA),
+  SET_USER: mb.commit(SET_USER),
+  SET_REFRESHING_TOKEN: mb.commit(SET_REFRESHING_TOKEN),
+  SET_LAST_TOKEN_REFRESH_TRY: mb.commit(SET_LAST_TOKEN_REFRESH_TRY),
+  RESET_STATE: mb.commit(RESET_STATE),
+
+  getJWT: mb.dispatch(getJWT),
+  refreshJWT: mb.dispatch(refreshJWT),
+  getUser: mb.dispatch(getUser),
+  getJWTTimeDelta: mb.dispatch(getJWTTimeDelta)
+}
diff --git a/frontend/src/store/modules/subscriptions.ts b/frontend/src/store/modules/subscriptions.ts
index 63dc6aae39c7fe91547d7728043efb5afaaaa110..12d678d652dacd0fc1d695ffa11a52a56e0d5d4a 100644
--- a/frontend/src/store/modules/subscriptions.ts
+++ b/frontend/src/store/modules/subscriptions.ts
@@ -4,6 +4,7 @@ import {cartesian, flatten, handleError, once} from '@/util/helpers'
 import {Assignment, Subscription} from '@/models'
 import {ActionContext, Module} from 'vuex'
 import {RootState} from '@/store/store'
+import { Authentication } from '@/store/modules/authentication';
 
 export const subscriptionMuts = Object.freeze({
   SET_SUBSCRIPTIONS: 'SET_SUBSCRIPTIONS',
@@ -39,21 +40,21 @@ const subscriptionsModule: Module<SubscriptionsState, RootState> = {
   getters: {
     availableTypes (state, getters) {
       let types = ['random', 'submission_type']
-      if (getters.isReviewer) {
+      if (Authentication.isReviewer) {
         types.push('exam')
       }
       return types
     },
     availableStages (state, getters) {
       let stages = ['feedback-creation', 'feedback-validation']
-      if (getters.isReviewer) {
+      if (Authentication.isReviewer) {
         stages.push('feedback-conflict-resolution')
       }
       return stages
     },
     availableStagesReadable (state, getters) {
       let stages = ['create', 'validate']
-      if (getters.isReviewer) {
+      if (Authentication.isReviewer) {
         stages.push('resolve')
       }
       return stages
@@ -265,7 +266,7 @@ const subscriptionsModule: Module<SubscriptionsState, RootState> = {
             dispatch('subscribeTo', {type, stage})
           })
         case Subscription.QueryTypeEnum.Exam:
-          if (getters.isReviewer) {
+          if (Authentication.isReviewer) {
             const stageKeyCartesian = cartesian(
               getters.availableStages, getters.availableExamTypeQueryKeys)
             // @ts-ignore
diff --git a/frontend/src/store/modules/ui.ts b/frontend/src/store/modules/ui.ts
index 776384463438ccb8bfb091c4118d568a3e350abd..04baacf7e6228f51641321beb1d29ea6bacfc4aa 100644
--- a/frontend/src/store/modules/ui.ts
+++ b/frontend/src/store/modules/ui.ts
@@ -19,10 +19,8 @@ function initialState (): UIState {
 
 const mb = getStoreBuilder<RootState>().module('UI', initialState())
 
-
 const stateGetter = mb.state()
 
-
 function SET_SIDEBAR_COLLAPSED (state: UIState, collapsed: boolean) {
   state.sideBarCollapsed = collapsed
 }
@@ -37,7 +35,7 @@ function SET_SHOW_JUMBOTRON (state: UIState, val: boolean) {
 }
 
 export const UI = {
-  get state() { return stateGetter() },
+  get state () { return stateGetter() },
 
   SET_SIDEBAR_COLLAPSED: mb.commit(SET_SIDEBAR_COLLAPSED),
   SET_DARK_MODE: mb.commit(SET_DARK_MODE),
diff --git a/frontend/src/store/store.ts b/frontend/src/store/store.ts
index e6ca81843fe422c872d6b243693148cac3df715c..c2c4b9ca300327dbc0260a37fd6f3f44745bc22e 100644
--- a/frontend/src/store/store.ts
+++ b/frontend/src/store/store.ts
@@ -5,17 +5,20 @@ import {getStoreBuilder} from 'vuex-typex'
 
 import studentPage from './modules/student-page'
 import submissionNotes from './modules/submission-notes'
-import authentication from './modules/authentication'
 import subscriptions from './modules/subscriptions'
 import feedbackTable from './modules/feedback_list/feedback-table'
 import feedbackSearchOptions from './modules/feedback_list/feedback-search-options'
 
+import './modules/ui'
+import './modules/authentication'
+
 import './mutations'
 import './actions'
 import './getters'
 
-import './modules/ui'
+
 import {UIState} from './modules/ui'
+import {AuthState} from './modules/authentication'
 
 import {lastInteraction} from '@/store/plugins/lastInteractionPlugin'
 import {
@@ -41,7 +44,8 @@ export interface RootInitialState {
 }
 
 export interface RootState extends RootInitialState{
-    UI: UIState
+    UI: UIState,
+    Authentication: AuthState
 }
 
 export function initialState (): RootInitialState {
@@ -68,7 +72,6 @@ export const persistedStateKey = 'grady'
 const store = getStoreBuilder<RootState>().vuexStore({
   strict: process.env.NODE_ENV === 'development',
   modules: {
-    authentication,
     studentPage,
     submissionNotes,
     subscriptions,
@@ -79,12 +82,12 @@ const store = getStoreBuilder<RootState>().vuexStore({
     createPersistedState({
       key: persistedStateKey,
       storage: window.sessionStorage,
-      // authentication.token is manually saved since using it with this plugin caused issues
+      // Authentication.token is manually saved since using it with this plugin caused issues
       // when manually reloading the page
       paths: Object.keys(initialState()).concat(
         ['UI', 'studentPage', 'submissionNotes', 'feedbackSearchOptions', 'subscriptions',
-          'authentication.user', 'authentication.jwtTimeDelta',
-          'authentication.tokenCreationTime'])
+          'Authentication.user', 'Authentication.jwtTimeDelta',
+          'Authentication.tokenCreationTime'])
     }),
     lastInteraction],
   // TODO is there a better way than casting the initialState ?